jrivard %!s(int64=10) %!d(string=hai) anos
pai
achega
46a1c55d89
Modificáronse 94 ficheiros con 1713 adicións e 712 borrados
  1. 6 0
      pwm/servlet/src/password/pwm/AppProperty.java
  2. 7 1
      pwm/servlet/src/password/pwm/AppProperty.properties
  3. 10 43
      pwm/servlet/src/password/pwm/PwmConstants.java
  4. 1 2
      pwm/servlet/src/password/pwm/PwmConstants.properties
  5. 6 1
      pwm/servlet/src/password/pwm/config/ActionConfiguration.java
  6. 8 0
      pwm/servlet/src/password/pwm/config/Configuration.java
  7. 7 7
      pwm/servlet/src/password/pwm/config/PwmSetting.xml
  8. 5 5
      pwm/servlet/src/password/pwm/config/PwmSettingCategory.java
  9. 16 28
      pwm/servlet/src/password/pwm/config/StoredConfiguration.java
  10. 4 1
      pwm/servlet/src/password/pwm/config/StoredValue.java
  11. 7 0
      pwm/servlet/src/password/pwm/config/value/AbstractValue.java
  12. 6 0
      pwm/servlet/src/password/pwm/config/value/BooleanValue.java
  13. 5 0
      pwm/servlet/src/password/pwm/config/value/FileValue.java
  14. 5 0
      pwm/servlet/src/password/pwm/config/value/PasswordValue.java
  15. 4 0
      pwm/servlet/src/password/pwm/http/PwmURL.java
  16. 27 1
      pwm/servlet/src/password/pwm/http/bean/NewUserBean.java
  17. 1 1
      pwm/servlet/src/password/pwm/http/filter/ApplicationModeFilter.java
  18. 24 6
      pwm/servlet/src/password/pwm/http/servlet/CaptchaServlet.java
  19. 8 8
      pwm/servlet/src/password/pwm/http/servlet/ConfigEditorServlet.java
  20. 4 1
      pwm/servlet/src/password/pwm/http/servlet/ForgottenPasswordServlet.java
  21. 36 13
      pwm/servlet/src/password/pwm/http/servlet/NewUserServlet.java
  22. 2 2
      pwm/servlet/src/password/pwm/http/servlet/ShortcutServlet.java
  23. 71 0
      pwm/servlet/src/password/pwm/http/tag/PwmScriptRefTag.java
  24. 11 2
      pwm/servlet/src/password/pwm/http/tag/PwmUrlTag.java
  25. 1 1
      pwm/servlet/src/password/pwm/i18n/Admin.properties
  26. 258 0
      pwm/servlet/src/password/pwm/i18n/LocaleHelper.java
  27. 77 0
      pwm/servlet/src/password/pwm/i18n/PwmLocaleBundle.java
  28. 1 14
      pwm/servlet/src/password/pwm/ldap/auth/AuthenticationRequest.java
  29. 63 0
      pwm/servlet/src/password/pwm/ldap/auth/AuthenticationUtility.java
  30. 0 157
      pwm/servlet/src/password/pwm/util/CodeIntegrityChecker.java
  31. 11 0
      pwm/servlet/src/password/pwm/util/SecureHelper.java
  32. 78 9
      pwm/servlet/src/password/pwm/util/operations/ActionExecutor.java
  33. 35 6
      pwm/servlet/src/password/pwm/util/operations/CrService.java
  34. 1 1
      pwm/servlet/src/password/pwm/util/stats/StatisticsManager.java
  35. 1 1
      pwm/servlet/src/password/pwm/ws/server/RestServerHelper.java
  36. 1 1
      pwm/servlet/src/password/pwm/ws/server/rest/RestCheckPasswordServer.java
  37. 1 1
      pwm/servlet/web/WEB-INF/jsp/admin-activity.jsp
  38. 2 2
      pwm/servlet/web/WEB-INF/jsp/admin-analysis.jsp
  39. 19 23
      pwm/servlet/web/WEB-INF/jsp/admin-dashboard.jsp
  40. 1 1
      pwm/servlet/web/WEB-INF/jsp/admin-logview-window.jsp
  41. 1 1
      pwm/servlet/web/WEB-INF/jsp/admin-logview.jsp
  42. 1 1
      pwm/servlet/web/WEB-INF/jsp/admin-tokenlookup.jsp
  43. 5 22
      pwm/servlet/web/WEB-INF/jsp/captcha.jsp
  44. 2 3
      pwm/servlet/web/WEB-INF/jsp/changepassword-wait.jsp
  45. 1 1
      pwm/servlet/web/WEB-INF/jsp/changepassword.jsp
  46. 8 8
      pwm/servlet/web/WEB-INF/jsp/configeditor.jsp
  47. 3 3
      pwm/servlet/web/WEB-INF/jsp/configguide-app.jsp
  48. 3 3
      pwm/servlet/web/WEB-INF/jsp/configguide-cr_storage.jsp
  49. 3 3
      pwm/servlet/web/WEB-INF/jsp/configguide-end.jsp
  50. 3 3
      pwm/servlet/web/WEB-INF/jsp/configguide-ldap.jsp
  51. 3 3
      pwm/servlet/web/WEB-INF/jsp/configguide-ldap2.jsp
  52. 3 3
      pwm/servlet/web/WEB-INF/jsp/configguide-ldap3.jsp
  53. 3 2
      pwm/servlet/web/WEB-INF/jsp/configguide-ldap_schema.jsp
  54. 4 3
      pwm/servlet/web/WEB-INF/jsp/configguide-ldapcert.jsp
  55. 3 2
      pwm/servlet/web/WEB-INF/jsp/configguide-password.jsp
  56. 4 4
      pwm/servlet/web/WEB-INF/jsp/configguide-start.jsp
  57. 3 3
      pwm/servlet/web/WEB-INF/jsp/configguide-template.jsp
  58. 1 1
      pwm/servlet/web/WEB-INF/jsp/configmanager-login.jsp
  59. 3 3
      pwm/servlet/web/WEB-INF/jsp/configmanager.jsp
  60. 1 1
      pwm/servlet/web/WEB-INF/jsp/forgottenpassword-attributes.jsp
  61. 1 1
      pwm/servlet/web/WEB-INF/jsp/forgottenpassword-responses.jsp
  62. 1 1
      pwm/servlet/web/WEB-INF/jsp/fragment/admin-nav.jsp
  63. 1 1
      pwm/servlet/web/WEB-INF/jsp/fragment/footer.jsp
  64. 1 1
      pwm/servlet/web/WEB-INF/jsp/fragment/header-warnings.jsp
  65. 2 2
      pwm/servlet/web/WEB-INF/jsp/helpdesk-detail.jsp
  66. 1 1
      pwm/servlet/web/WEB-INF/jsp/helpdesk.jsp
  67. 11 10
      pwm/servlet/web/WEB-INF/jsp/newuser-entercode.jsp
  68. 1 1
      pwm/servlet/web/WEB-INF/jsp/newuser-wait.jsp
  69. 14 24
      pwm/servlet/web/WEB-INF/jsp/newuser.jsp
  70. 1 1
      pwm/servlet/web/WEB-INF/jsp/peoplesearch.jsp
  71. 1 1
      pwm/servlet/web/WEB-INF/jsp/setupotpsecret-existing.jsp
  72. 1 1
      pwm/servlet/web/WEB-INF/jsp/setupotpsecret-success.jsp
  73. 1 1
      pwm/servlet/web/WEB-INF/jsp/setupotpsecret-test.jsp
  74. 1 1
      pwm/servlet/web/WEB-INF/jsp/setupotpsecret.jsp
  75. 1 1
      pwm/servlet/web/WEB-INF/jsp/setupresponses-helpdesk.jsp
  76. 1 1
      pwm/servlet/web/WEB-INF/jsp/setupresponses.jsp
  77. 3 11
      pwm/servlet/web/WEB-INF/jsp/shortcut.jsp
  78. 1 1
      pwm/servlet/web/WEB-INF/jsp/updateprofile.jsp
  79. 12 1
      pwm/servlet/web/WEB-INF/pwm-taglib.tld
  80. 1 1
      pwm/servlet/web/public/health.jsp
  81. 2 2
      pwm/servlet/web/public/randomgen.jsp
  82. 26 26
      pwm/servlet/web/public/reference/license.jsp
  83. 413 0
      pwm/servlet/web/public/reference/localeinfo.jsp
  84. 3 2
      pwm/servlet/web/public/reference/referencedoc.jsp
  85. 1 1
      pwm/servlet/web/public/reference/rest.jsp
  86. 0 0
      pwm/servlet/web/public/reference/timezones.jsp
  87. 15 10
      pwm/servlet/web/public/resources/configStyle.css
  88. 2 19
      pwm/servlet/web/public/resources/js/admin.js
  89. 7 0
      pwm/servlet/web/public/resources/js/changepassword.js
  90. 161 143
      pwm/servlet/web/public/resources/js/configeditor-settings.js
  91. 5 3
      pwm/servlet/web/public/resources/js/configeditor.js
  92. 81 25
      pwm/servlet/web/public/resources/js/main.js
  93. 46 1
      pwm/servlet/web/public/resources/style.css
  94. 5 5
      pwm/servlet/web/public/resources/themes/pwm/style.css

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

@@ -132,6 +132,9 @@ public enum AppProperty {
     NMAS_THREADS_MIN_SECONDS                        ("nmas.threads.minSeconds"),
     NMAS_THREADS_MAX_SECONDS                        ("nmas.threads.maxSeconds"),
     NMAS_THREADS_WATCHDOG_FREQUENCY                 ("nmas.threads.watchdogFrequencyMs"),
+    NMAS_CR_MIN_RANDOM_DURING_SETUP                 ("nmas.cr.minRandomDuringSetup"),
+    NMAS_CR_APPLY_WORDLIST                          ("nmas.cr.applyWordlist"),
+    NMAS_CR_MAX_QUESTION_CHARS_IN__ANSWER           ("nmas.cr.maxQuestionCharsInAnswer"),
     OAUTH_ID_REQUEST_TYPE                           ("oauth.id.requestType"),
     OAUTH_ID_ACCESS_GRANT_TYPE                      ("oauth.id.accessGrantType"),
     OAUTH_ID_REFRESH_GRANT_TYPE                     ("oauth.id.refreshGrantType"),
@@ -163,6 +166,9 @@ public enum AppProperty {
     QUEUE_SYSLOG_MAX_AGE_MS                         ("queue.syslog.maxAgeMs"),
     QUEUE_SYSLOG_MAX_COUNT                          ("queue.syslog.maxCount"),
     QUEUE_MAX_CLOSE_TIMEOUT_MS                      ("queue.maxCloseTimeoutMs"),
+    RECAPTCHA_CLIENT_JS_URL("recaptcha.clientJsUrl"),
+    RECAPTCHA_CLIENT_IFRAME_URL                     ("recaptcha.clientIframeUrl"),
+    RECAPTCHA_VALIDATE_URL                          ("recaptcha.validateUrl"),
     REPORTING_LDAP_SEARCH_TIMEOUT                   ("reporting.ldap.searchTimeoutMs"),
     SECURITY_STRIP_INLINE_JAVASCRIPT                ("security.html.stripInlineJavascript"),
     SECURITY_HTTP_STRIP_HEADER_REGEX                ("security.http.stripHeaderRegex"),

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

@@ -122,6 +122,9 @@ nmas.threads.maxCount=120
 nmas.threads.minSeconds=1800
 nmas.threads.maxSeconds=3000
 nmas.threads.watchdogFrequencyMs=1000
+nmas.cr.minRandomDuringSetup=0
+nmas.cr.applyWordlist=false
+nmas.cr.maxQuestionCharsInAnswer=0
 oauth.id.accessGrantType=authorization_code
 oauth.id.refreshGrantType=refresh_token
 oauth.id.requestType=code
@@ -134,7 +137,7 @@ otp.recovery.macro=@RandomChar:8:0123456789@
 otp.recoveryHash.iterations=1000
 otp.recoveryHash.method=SHA1
 password.randomGenerator.maxAttempts=2000
-password.randomGenerator.maxLength=100
+password.randomGenerator.maxLength=1024
 password.randomGenerator.jitter.count=50
 peoplesearch.displayName.enableAllMacros=false
 peoplesearch.maxValueCount=100
@@ -149,6 +152,9 @@ queue.syslog.maxAgeMs=86400000
 queue.syslog.maxCount=100000
 queue.maxCloseTimeoutMs=5000
 reporting.ldap.searchTimeoutMs=300000
+recaptcha.clientJsUrl=//www.google.com/recaptcha/api/js/recaptcha_ajax.js
+recaptcha.clientIframeUrl=//www.google.com/recaptcha/api/noscript
+recaptcha.validateUrl=http://www.google.com/recaptcha/api/verify
 security.html.stripInlineJavascript=false
 security.http.stripHeaderRegex=\\n|\\r|(?ism)%0A|%0D
 security.responses.hashIterations=100000

+ 10 - 43
pwm/servlet/src/password/pwm/PwmConstants.java

@@ -24,14 +24,14 @@ package password.pwm;
 
 import org.apache.commons.csv.CSVFormat;
 import password.pwm.bean.SessionLabel;
-import password.pwm.i18n.Display;
-import password.pwm.i18n.Health;
-import password.pwm.i18n.Message;
 
 import java.nio.charset.Charset;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
-import java.util.*;
+import java.util.Date;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.TimeZone;
 
 /**
  * Constant values used throughout the servlet.
@@ -99,8 +99,6 @@ public abstract class PwmConstants {
     public static final int TRIAL_MAX_AUTHENTICATIONS = 100;
     public static final int TRIAL_MAX_TOTAL_AUTH = 10000;
 
-    public static final String RECAPTCHA_VALIDATE_URL = readPwmConstantsBundle("recaptchaValidateUrl");
-
     private static final String SESSION_LABEL_SESSION_ID = "#";
     public static final SessionLabel REPORTING_SESSION_LABEL = new SessionLabel(SESSION_LABEL_SESSION_ID ,null,"reporting",null,null);
     public static final SessionLabel HEALTH_SESSION_LABEL = new SessionLabel(SESSION_LABEL_SESSION_ID ,null,"health",null,null);
@@ -140,7 +138,12 @@ public abstract class PwmConstants {
         FormConfiguration,
         FormReadOnly,
         FormShowPasswordFields,
-        FormData, ConfigFilename, ConfigLastModified, ConfigHasPassword,
+        FormData,
+        ConfigFilename,
+        ConfigLastModified,
+        ConfigHasPassword,
+
+        CaptchaClientUrl, CaptchaIframeUrl, CaptchaPublicKey,
     }
 
 
@@ -334,42 +337,6 @@ public abstract class PwmConstants {
 // -------------------------- ENUMERATIONS --------------------------
 
 
-    public static enum PwmLocaleBundle {
-        DISPLAY(Display.class, false),
-        ERRORS(password.pwm.i18n.Error.class, false),
-        MESSAGE(Message.class, false),
-
-        CONFIG(password.pwm.i18n.Config.class, true),
-        ADMIN(password.pwm.i18n.Admin.class, true),
-        HEALTH(Health.class, true),
-        ;
-
-        private final Class theClass;
-        private final boolean adminOnly;
-        private Set<String> keys = null;
-
-        PwmLocaleBundle(final Class theClass, final boolean adminOnly) {
-            this.theClass = theClass;
-            this.adminOnly = adminOnly;
-        }
-
-        public Class getTheClass() {
-            return theClass;
-        }
-
-        public boolean isAdminOnly() {
-            return adminOnly;
-        }
-
-        public Set<String> getKeys() {
-            if (keys == null) {
-                final ResourceBundle defaultBundle = ResourceBundle.getBundle(this.getTheClass().getName(), PwmConstants.DEFAULT_LOCALE);
-                keys = Collections.unmodifiableSet(new HashSet<>(defaultBundle.keySet()));
-            }
-            return keys;
-        }
-    }
-
     public enum HttpHeader {
         Accept("Accept"),
         Connection("Connection"),

+ 1 - 2
pwm/servlet/src/password/pwm/PwmConstants.properties

@@ -3,7 +3,7 @@
 # http://code.google.com/p/pwm/
 #
 # Copyright (c) 2006-2009 Novell, Inc.
-# Copyright (c) 2009-2014 The PWM Project
+# Copyright (c) 2009-2015 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
@@ -46,5 +46,4 @@ pwmDBLoggerMaxQueueSize=50000
 pwmDBLoggerMaxDirtyBufferMS=500
 enableEulaDisplay=false
 databaseAccessor.keyLength=128
-recaptchaValidateUrl=http://www.google.com/recaptcha/api/verify
 missingVersionString=[Missing_Version_#]

+ 6 - 1
pwm/servlet/src/password/pwm/config/ActionConfiguration.java

@@ -32,6 +32,7 @@ public class ActionConfiguration implements Serializable {
 
     public enum Type { webservice, ldap }
     public enum WebMethod { delete, get, post, put }
+    public enum LdapMethod { replace, add, remove }
 
     private String name;
     private String description;
@@ -39,11 +40,11 @@ public class ActionConfiguration implements Serializable {
     private Type type = Type.webservice;
 
     private WebMethod method = WebMethod.get;
-    //private boolean clientSide;
     private Map<String,String> headers;
     private String url;
     private String body;
 
+    private LdapMethod ldapMethod = LdapMethod.replace;
     private String attributeName;
     private String attributeValue;
 
@@ -67,6 +68,10 @@ public class ActionConfiguration implements Serializable {
         return url;
     }
 
+    public LdapMethod getLdapMethod() {
+        return ldapMethod;
+    }
+
     public Map<String, String> getHeaders() {
         return headers;
     }

+ 8 - 0
pwm/servlet/src/password/pwm/config/Configuration.java

@@ -825,4 +825,12 @@ public class Configuration implements Serializable, SettingReader {
     {
         return storedConfiguration.settingChecksum();
     }
+
+    public Set<PwmSetting> nonDefaultSettings() {
+        final HashSet returnSet = new HashSet();
+        for (StoredConfiguration.SettingValueRecord valueRecord : this.storedConfiguration.modifiedSettings()) {
+            returnSet.add(valueRecord.getSetting());
+        }
+        return returnSet;
+    }
 }

+ 7 - 7
pwm/servlet/src/password/pwm/config/PwmSetting.xml

@@ -1444,7 +1444,7 @@
             <value>0</value>
         </default>
     </setting>
-    <setting key="pwm.securityKey" level="2">
+    <setting key="pwm.securityKey" level="0">
         <label>Security Key</label>
         <description><![CDATA[<p>A Security Key used for cryptographic functions such as the token verification. A value is required if tokens are enabled for any of modules and a token storage method has been configured. This value is used similar to how the private key in a cryptographic security certificate is used.</p> <p>If configured, this value must be at least 32 characters in length.  The longer and more random this value, the more secure its use will be.  If multiple instances are in use, each instance should be configured with the same value.</p><p>Upon initial setup, a random security key is assigned to this value, it can be changed at any time, however any outstanding tokens or other material generated by an old security key will become invalid.</p>]]></description>
         <regex>.{32}.*</regex>
@@ -2487,7 +2487,7 @@
     </setting>
     <setting key="forgottenUsername.searchFilter" level="2">
         <label>Forgotten Username Search Filter</label>
-        <description><![CDATA[LDAP search filter used to search for users during forgotten username recovery. &nbsp;The LDAP search filter should include each attribute in the <i>Forgotten Username Form</i>.  Tokens made of a form item name (such as <code>cn</code>) enclosed with a percent sign <code>%cn%</code> will be replaced with values supplied by the user.<br><br>For example, if the <i>Forgotten Username Form</i> included the attributes <code>cn</code> and <code>sn</code>, then this filter may be appropriate:<br><br><code>(&amp;(objectClass=person)(cn=%cn%)(sn=%sn%))</code><br><br>If this setting is left blank, a search filter based on the required items in the <i>Forgotten Username Form</i> will be automatically generated.]]></description>
+        <description><![CDATA[LDAP search filter used to search for users during forgotten username recovery. &nbsp;The LDAP search filter should include each attribute in the <i>Forgotten Username Form</i>.  Tokens made of a form item name (such as <code>cn</code>) enclosed with a percent sign <code>%cn%</code> will be replaced with values supplied by the user.<br><br>For example, if the <i>Forgotten Username Form</i> included the attributes <code>cn</code> and <code>sn</code>, then this filter may be appropriate:<br><br><code>(&amp;(objectClass=person)(cn=%cn%)(sn=%sn%))</code><br><br>If this setting is left blank, a search filter based on the required items in the <i>Forgotten Username Form</i> will be automatically generated at the time of the search.]]></description>
         <default/>
     </setting>
     <setting key="forgottenUsername.usernameAttribute" level="1" required="true">
@@ -2559,7 +2559,7 @@
     </setting>
     <setting key="newUser.writeAttributes" level="1">
         <label>New User Actions</label>
-        <description><![CDATA[Actions to be taken when a user is created.  These actions will be executed just after creating the object.<br/><br/>The format is name=value pair, multiple attributes can be specified by separating with a comma.  Macros may be used.]]></description>
+        <description><![CDATA[Actions to be taken when a user is created.  These actions will be executed just after creating the object.]]></description>
         <default />
     </setting>
     <setting key="newUser.deleteOnFail" level="2">
@@ -3460,7 +3460,7 @@
         <label>Challenge/Response Verification</label>
         <description><![CDATA[]]></description>
         <default>
-            <value><![CDATA[NONE]]></value>
+            <value><![CDATA[REQUIRED]]></value>
         </default>
         <options>
             <option value="NONE">None</option>
@@ -4060,7 +4060,7 @@
         <description><![CDATA[]]></description>
     </category>
     <category key="LDAP_GLOBAL">
-        <label>LDAP Settings</label>
+        <label>General LDAP Settings</label>
         <description><![CDATA[Global settings that control the interaction with an LDAP directory.  These settings are applied regardless of the user's LDAP profile.  For profile-specific settings, see Profiles -> LDAP Directory Profiles.]]></description>
     </category>
     <category key="GENERAL">
@@ -4259,11 +4259,11 @@
         <description><![CDATA[New user self registration settings.  The new user registration module requires that the proxy user has sufficient permissions to create users and, if so configured, to check for duplicate values.  New users are created in the default LDAP directory profile.]]></description>
     </category>
     <category key="NEWUSER_SETTINGS">
-        <label>Settings</label>
+        <label>New User Settings</label>
         <description><![CDATA[New user self registration settings.  The new user registration module requires that the proxy user has sufficient permissions to create users and, if so configured, to check for duplicate values.  New users are created in the default LDAP directory profile.]]></description>
     </category>
     <category key="NEWUSER_PROFILE" profiles="true">
-        <label>Profiles</label>
+        <label>New User Profiles</label>
         <description><![CDATA[New user self registration settings.  The new user registration module requires that the proxy user has sufficient permissions to create users and, if so configured, to check for duplicate values.  New users are created in the default LDAP directory profile.]]></description>
         <profile setting="newUser.profile.list"/>
     </category>

+ 5 - 5
pwm/servlet/src/password/pwm/config/PwmSettingCategory.java

@@ -29,14 +29,14 @@ import java.util.*;
 
 public enum PwmSettingCategory {
 
-    LDAP_PROFILE(null),
-    SETTINGS(null),
-    PROFILES(null),
-    MODULES(null),
+    LDAP                        (null),
+    SETTINGS                    (null),
+    PROFILES                    (null),
+    MODULES                     (null),
 
     GENERAL                     (SETTINGS),
-    LDAP                        (SETTINGS),
 
+    LDAP_PROFILE                (LDAP),
     LDAP_GLOBAL                 (LDAP),
     EDIRECTORY                  (LDAP),
     ACTIVE_DIRECTORY            (LDAP),

+ 16 - 28
pwm/servlet/src/password/pwm/config/StoredConfiguration.java

@@ -34,6 +34,7 @@ import password.pwm.config.value.StringArrayValue;
 import password.pwm.config.value.StringValue;
 import password.pwm.config.value.ValueFactory;
 import password.pwm.error.*;
+import password.pwm.i18n.PwmLocaleBundle;
 import password.pwm.util.*;
 import password.pwm.util.logging.PwmLogger;
 
@@ -217,8 +218,6 @@ public class StoredConfiguration implements Serializable {
             final ConfigProperty propertyName,
             final String value
     ) {
-        preModifyActions();
-
         domModifyLock.writeLock().lock();
         try {
 
@@ -685,7 +684,7 @@ public class StoredConfiguration implements Serializable {
 
     public void writeLocaleBundleMap(final String bundleName, final String keyName, final Map<String,String> localeMap) {
         ResourceBundle theBundle = null;
-        for (final PwmConstants.PwmLocaleBundle bundle : PwmConstants.PwmLocaleBundle.values()) {
+        for (final PwmLocaleBundle bundle : PwmLocaleBundle.values()) {
             if (bundle.getTheClass().getName().equals(bundleName)) {
                 theBundle = ResourceBundle.getBundle(bundleName);
             }
@@ -783,35 +782,23 @@ public class StoredConfiguration implements Serializable {
         }
     }
 
-    public String settingChecksum() throws PwmUnrecoverableException {
+    public String settingChecksum()
+            throws PwmUnrecoverableException
+    {
+        final Date startTime = new Date();
+
+        final List<SettingValueRecord> modifiedSettings = modifiedSettings();
         final StringBuilder sb = new StringBuilder();
         sb.append("PwmSettingsChecksum");
-
-        for (final PwmSetting setting : PwmSetting.values()) {
-            if (setting.getSyntax() != PwmSettingSyntax.PROFILE && !setting.getCategory().hasProfiles()) {
-                if (!isDefaultValue(setting,null)) {
-                    final StoredValue value = readSetting(setting);
-                    sb.append(setting.getKey()).append(JsonUtil.serialize(value));
-                }
-            }
+        for (SettingValueRecord settingValueRecord : modifiedSettings) {
+            final StoredValue storedValue = settingValueRecord.getStoredValue();
+            sb.append(storedValue.valueHash());
         }
 
-        for (final PwmSettingCategory category : PwmSettingCategory.values()) {
-            if (category.hasProfiles()) {
-                for (final String profileID : this.profilesForSetting(category.getProfileSetting())) {
-                    for (final PwmSetting profileSetting : category.getSettings()) {
-                        if (!isDefaultValue(profileSetting, profileID)) {
-                            final StoredValue value = readSetting(profileSetting, profileID);
-                            sb.append(profileSetting.getKey()).append(profileID).append(JsonUtil.serialize(value));
-                        }
-                    }
-                }
-            }
-        }
 
-        sb.append(createTime());
-
-        return SecureHelper.hash(sb.toString(),SecureHelper.DEFAULT_HASH_ALGORITHM);
+        final String result = SecureHelper.hash(sb.toString());
+        LOGGER.trace("computed setting checksum in " + TimeDuration.fromCurrent(startTime).asCompactString());
+        return result;
     }
 
 
@@ -1207,7 +1194,7 @@ public class StoredConfiguration implements Serializable {
             }
             final StringBuilder output = new StringBuilder();
             if (outputMap.isEmpty()) {
-                output.append("No changes.");
+                output.append("No setting changes.");
             } else {
                 for (final String keyName : outputMap.keySet()) {
                     final String value = outputMap.get(keyName);
@@ -1441,4 +1428,5 @@ public class StoredConfiguration implements Serializable {
         
         LOGGER.debug("initialized new random security key");
     }
+
 }

+ 4 - 1
pwm/servlet/src/password/pwm/config/StoredValue.java

@@ -3,7 +3,7 @@
  * http://code.google.com/p/pwm/
  *
  * Copyright (c) 2006-2009 Novell, Inc.
- * Copyright (c) 2009-2014 The PWM Project
+ * Copyright (c) 2009-2015 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
@@ -24,6 +24,7 @@ package password.pwm.config;
 
 import org.jdom2.Element;
 import password.pwm.error.PwmException;
+import password.pwm.error.PwmUnrecoverableException;
 
 import java.io.Serializable;
 import java.util.List;
@@ -51,4 +52,6 @@ public interface StoredValue extends Serializable {
         StoredValue fromXmlElement(final Element settingElement, final String key)
                 throws PwmException;
     }
+
+    String valueHash() throws PwmUnrecoverableException;
 }

+ 7 - 0
pwm/servlet/src/password/pwm/config/value/AbstractValue.java

@@ -23,7 +23,9 @@
 package password.pwm.config.value;
 
 import password.pwm.config.StoredValue;
+import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.JsonUtil;
+import password.pwm.util.SecureHelper;
 
 import java.io.Serializable;
 import java.util.Locale;
@@ -49,4 +51,9 @@ public abstract class AbstractValue implements StoredValue {
     {
         return 0;
     }
+
+    @Override
+    public String valueHash() throws PwmUnrecoverableException {
+        return SecureHelper.hash(JsonUtil.serialize((Serializable)this.toNativeObject()));
+    }
 }

+ 6 - 0
pwm/servlet/src/password/pwm/config/value/BooleanValue.java

@@ -26,6 +26,7 @@ import org.jdom2.Element;
 import password.pwm.PwmConstants;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.StoredValue;
+import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.i18n.Display;
 import password.pwm.util.JsonUtil;
 
@@ -97,4 +98,9 @@ public class BooleanValue implements StoredValue {
     {
         return 0;
     }
+
+    @Override
+    public String valueHash() throws PwmUnrecoverableException {
+        return value ? "1" : "0";
+    }
 }

+ 5 - 0
pwm/servlet/src/password/pwm/config/value/FileValue.java

@@ -243,4 +243,9 @@ public class FileValue extends AbstractValue implements StoredValue {
         }
         return Collections.unmodifiableList(returnObj);
     }
+
+    @Override
+    public String valueHash() throws PwmUnrecoverableException {
+        return SecureHelper.hash(JsonUtil.serializeCollection(toInfoMap()));
+    }
 }

+ 5 - 0
pwm/servlet/src/password/pwm/config/value/PasswordValue.java

@@ -166,4 +166,9 @@ public class PasswordValue implements StoredValue {
     {
         return requiresStoredUpdate;
     }
+
+    @Override
+    public String valueHash() throws PwmUnrecoverableException {
+        return value == null ? "" : SecureHelper.hash(JsonUtil.serialize(value.getStringValue()));
+    }
 }

+ 4 - 0
pwm/servlet/src/password/pwm/http/PwmURL.java

@@ -55,6 +55,10 @@ public class PwmURL {
         return checkIfStartsWithURL("/public/resources/");
     }
 
+    public boolean isReferenceURL() {
+        return checkIfStartsWithURL("/public/reference/");
+    }
+
     public boolean isLogoutURL() {
         return checkIfStartsWithURL("/private/" + PwmConstants.URL_SERVLET_LOGOUT)
                 || checkIfStartsWithURL("/public/" + PwmConstants.URL_SERVLET_LOGOUT);

+ 27 - 1
pwm/servlet/src/password/pwm/http/bean/NewUserBean.java

@@ -23,9 +23,11 @@
 package password.pwm.http.bean;
 
 import password.pwm.config.FormConfiguration;
+import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.servlet.NewUserServlet;
 import password.pwm.util.PasswordData;
 
+import java.io.Serializable;
 import java.util.Date;
 import java.util.Map;
 
@@ -45,7 +47,7 @@ public class NewUserBean implements PwmSessionBean {
     private Date createStartTime;
     private NewUserServlet.Page currentPage;
 
-    public static class NewUserForm {
+    public static class NewUserForm implements Serializable {
         private Map<FormConfiguration,String> formData;
         private PasswordData newUserPassword;
         private PasswordData confirmPassword;
@@ -75,6 +77,30 @@ public class NewUserBean implements PwmSessionBean {
         {
             return confirmPassword;
         }
+
+        public boolean isConsistentWith(NewUserForm otherForm) throws PwmUnrecoverableException {
+            if (otherForm == null) {
+                return false;
+            }
+
+            if (newUserPassword != null && otherForm.newUserPassword == null || newUserPassword == null && otherForm.newUserPassword != null) {
+                return false;
+            }
+
+            if (newUserPassword == null || !newUserPassword.getStringValue().equals(otherForm.newUserPassword.getStringValue())) {
+                return false;
+            }
+
+            for (final FormConfiguration formConfiguration : formData.keySet()) {
+                final String value = formData.get(formConfiguration);
+                final String otherValue = otherForm.formData.get(formConfiguration);
+                if (value != null && !value.equals(otherValue)) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
     }
 
     public String getProfileID() {

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

@@ -51,7 +51,7 @@ public class ApplicationModeFilter extends AbstractPwmFilter {
 
         // ignore if resource request
         final PwmURL pwmURL = pwmRequest.getURL();
-        if (!pwmURL.isResourceURL() && !pwmURL.isWebServiceURL()) {
+        if (!pwmURL.isResourceURL() && !pwmURL.isWebServiceURL() && !pwmURL.isReferenceURL()) {
             // check for valid config
             try {
                 if (checkConfigModes(pwmRequest)) {

+ 24 - 6
pwm/servlet/src/password/pwm/http/servlet/CaptchaServlet.java

@@ -3,7 +3,7 @@
  * http://code.google.com/p/pwm/
  *
  * Copyright (c) 2006-2009 Novell, Inc.
- * Copyright (c) 2009-2014 The PWM Project
+ * Copyright (c) 2009-2015 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
@@ -29,6 +29,7 @@ import org.apache.http.HttpStatus;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.util.EntityUtils;
+import password.pwm.AppProperty;
 import password.pwm.PwmApplication;
 import password.pwm.PwmConstants;
 import password.pwm.bean.SessionStateBean;
@@ -44,6 +45,7 @@ import password.pwm.util.ServletHelper;
 import password.pwm.util.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.stats.Statistic;
+import password.pwm.util.stats.StatisticsManager;
 
 import javax.servlet.ServletException;
 import java.io.IOException;
@@ -59,8 +61,6 @@ public class CaptchaServlet extends PwmServlet {
     private static final String SKIP_COOKIE_NAME = "captcha-key";
     private static final String COOKIE_SKIP_INSTANCE_VALUE = "INSTANCEID";
 
-    private static final String RECAPTCHA_VALIDATE_URL = PwmConstants.RECAPTCHA_VALIDATE_URL;
-
     public enum CaptchaAction implements PwmServlet.ProcessAction {
         doVerify,
         ;
@@ -107,7 +107,7 @@ public class CaptchaServlet extends PwmServlet {
         }
 
         if (!pwmRequest.getPwmResponse().isCommitted()) {
-            pwmRequest.forwardToJsp(PwmConstants.JSP_URL.CAPTCHA);
+            forwardToCaptchaPage(pwmRequest);
         }
     }
 
@@ -142,7 +142,7 @@ public class CaptchaServlet extends PwmServlet {
             LOGGER.debug(pwmSession, "incorrect captcha passcode");
             pwmApplication.getIntruderManager().convenience().markAddressAndSession(pwmSession);
             pwmRequest.setResponseError(PwmError.ERROR_BAD_CAPTCHA_RESPONSE.toInfo());
-            pwmRequest.forwardToJsp(PwmConstants.JSP_URL.CAPTCHA);
+            forwardToCaptchaPage(pwmRequest);
         }
     }
 
@@ -167,7 +167,8 @@ public class CaptchaServlet extends PwmServlet {
         bodyText.append("response=").append(pwmRequest.readParameterAsString("recaptcha_response_field"));
 
         try {
-            final URI requestURI = new URI(RECAPTCHA_VALIDATE_URL);
+            final String configuredURI = pwmApplication.getConfig().readAppProperty(AppProperty.RECAPTCHA_VALIDATE_URL);
+            final URI requestURI = new URI(configuredURI);
             final HttpPost httpPost = new HttpPost(requestURI.toString());
             httpPost.setHeader("Content-Type", PwmConstants.ContentTypeValue.form.getHeaderValue());
             httpPost.setEntity(new StringEntity(bodyText.toString(),PwmConstants.DEFAULT_CHARSET));
@@ -273,4 +274,21 @@ public class CaptchaServlet extends PwmServlet {
         }
         return false;
     }
+
+    private void forwardToCaptchaPage(final PwmRequest pwmRequest) throws ServletException, PwmUnrecoverableException, IOException {
+        StatisticsManager.incrementStat(pwmRequest, Statistic.CAPTCHA_PRESENTATIONS);
+
+        final String reCaptchaPublicKey = pwmRequest.getConfig().readSettingAsString(PwmSetting.RECAPTCHA_KEY_PUBLIC);
+        pwmRequest.setAttribute(PwmConstants.REQUEST_ATTR.CaptchaPublicKey, reCaptchaPublicKey);
+        {
+            final String urlValue = pwmRequest.getConfig().readAppProperty(AppProperty.RECAPTCHA_CLIENT_JS_URL);
+            pwmRequest.setAttribute(PwmConstants.REQUEST_ATTR.CaptchaClientUrl, urlValue);
+        }
+        {
+            final String configuredUrl =pwmRequest.getConfig().readAppProperty(AppProperty.RECAPTCHA_CLIENT_IFRAME_URL);
+            final String url = configuredUrl + "?k=" + reCaptchaPublicKey + "&hl=" + pwmRequest.getLocale().toString();
+            pwmRequest.setAttribute(PwmConstants.REQUEST_ATTR.CaptchaIframeUrl,url);
+        }
+        pwmRequest.forwardToJsp(PwmConstants.JSP_URL.CAPTCHA);
+    }
 }

+ 8 - 8
pwm/servlet/src/password/pwm/http/servlet/ConfigEditorServlet.java

@@ -40,6 +40,7 @@ import password.pwm.http.bean.ConfigManagerBean;
 import password.pwm.i18n.Config;
 import password.pwm.i18n.LocaleHelper;
 import password.pwm.i18n.Message;
+import password.pwm.i18n.PwmLocaleBundle;
 import password.pwm.util.JsonUtil;
 import password.pwm.util.StringUtil;
 import password.pwm.util.TimeDuration;
@@ -281,7 +282,7 @@ public class ConfigEditorServlet extends PwmServlet {
         if (key.startsWith("localeBundle")) {
             final StringTokenizer st = new StringTokenizer(key, "-");
             st.nextToken();
-            final PwmConstants.PwmLocaleBundle bundleName = PwmConstants.PwmLocaleBundle.valueOf(st.nextToken());
+            final PwmLocaleBundle bundleName = PwmLocaleBundle.valueOf(st.nextToken());
             final String keyName = st.nextToken();
             final Map<String, String> bundleMap = storedConfig.readLocaleBundleMap(bundleName.getTheClass().getName(), keyName);
             if (bundleMap == null || bundleMap.isEmpty()) {
@@ -371,7 +372,7 @@ public class ConfigEditorServlet extends PwmServlet {
         if (key.startsWith("localeBundle")) {
             final StringTokenizer st = new StringTokenizer(key, "-");
             st.nextToken();
-            final PwmConstants.PwmLocaleBundle bundleName = PwmConstants.PwmLocaleBundle.valueOf(st.nextToken());
+            final PwmLocaleBundle bundleName = PwmLocaleBundle.valueOf(st.nextToken());
             final String keyName = st.nextToken();
             final Map<String, String> valueMap = JsonUtil.deserializeStringMap(bodyString);
             final Map<String, String> outputMap = new LinkedHashMap<>(valueMap);
@@ -414,7 +415,7 @@ public class ConfigEditorServlet extends PwmServlet {
         if (key.startsWith("localeBundle")) {
             final StringTokenizer st = new StringTokenizer(key, "-");
             st.nextToken();
-            final PwmConstants.PwmLocaleBundle bundleName = PwmConstants.PwmLocaleBundle.valueOf(st.nextToken());
+            final PwmLocaleBundle bundleName = PwmLocaleBundle.valueOf(st.nextToken());
             final String keyName = st.nextToken();
             storedConfig.resetLocaleBundleMap(bundleName.getTheClass().getName(), keyName);
         } else {
@@ -721,8 +722,7 @@ public class ConfigEditorServlet extends PwmServlet {
                 categoryInfo.put("id", loopCategory.getKey());
                 categoryInfo.put("name", loopCategory.getLabel(pwmRequest.getLocale()));
 
-
-                if (loopCategory.getParent() != null && loopCategory != PwmSettingCategory.LDAP_PROFILE) {
+                if (loopCategory.getParent() != null) {
                     categoryInfo.put("parent", loopCategory.getParent().getKey());
                 } else {
                     categoryInfo.put("parent", "ROOT");
@@ -769,7 +769,7 @@ public class ConfigEditorServlet extends PwmServlet {
 
         boolean includeDisplayText = false;
         if (level >= 1) {
-            for (final PwmConstants.PwmLocaleBundle localeBundle : PwmConstants.PwmLocaleBundle.values()) {
+            for (final PwmLocaleBundle localeBundle : PwmLocaleBundle.values()) {
                 if (!localeBundle.isAdminOnly()) {
                     final Set<String> modifiedKeys = new TreeSet<>();
                     if (modifiedSettingsOnly) {
@@ -803,7 +803,7 @@ public class ConfigEditorServlet extends PwmServlet {
 
     private static class NavTreeHelper {
         private static Set<String> determineModifiedKeysSettings(
-                final PwmConstants.PwmLocaleBundle bundle,
+                final PwmLocaleBundle bundle,
                 final Configuration config,
                 final StoredConfiguration storedConfiguration
         ) {
@@ -929,7 +929,7 @@ public class ConfigEditorServlet extends PwmServlet {
         }
         {
             final LinkedHashMap<String, Object> labelMap = new LinkedHashMap<>();
-            for (final PwmConstants.PwmLocaleBundle localeBundle : PwmConstants.PwmLocaleBundle.values()) {
+            for (final PwmLocaleBundle localeBundle : PwmLocaleBundle.values()) {
                 final LocaleInfo localeInfo = new LocaleInfo();
                 localeInfo.description = localeBundle.getTheClass().getSimpleName();
                 localeInfo.key = localeBundle.toString();

+ 4 - 1
pwm/servlet/src/password/pwm/http/servlet/ForgottenPasswordServlet.java

@@ -54,6 +54,7 @@ import password.pwm.ldap.UserDataReader;
 import password.pwm.ldap.UserSearchEngine;
 import password.pwm.ldap.UserStatusReader;
 import password.pwm.ldap.auth.AuthenticationType;
+import password.pwm.ldap.auth.AuthenticationUtility;
 import password.pwm.ldap.auth.SessionAuthenticator;
 import password.pwm.token.TokenPayload;
 import password.pwm.token.TokenService;
@@ -350,6 +351,8 @@ public class ForgottenPasswordServlet extends PwmServlet {
                 return;
             }
 
+            AuthenticationUtility.checkIfUserEligibleToAuthentication(pwmApplication, userIdentity);
+
             final ForgottenPasswordBean forgottenPasswordBean = pwmRequest.getPwmSession().getForgottenPasswordBean();
             initForgottenPasswordBean(pwmApplication, pwmRequest.getLocale(), pwmRequest.getSessionLabel(),userIdentity, forgottenPasswordBean);
 
@@ -579,7 +582,7 @@ public class ForgottenPasswordServlet extends PwmServlet {
             }
         }
 
-        // redirect if an verificiation method is in progress
+        // redirect if an verification method is in progress
         if (progress.getInProgressVerificationMethod() != null) {
             if (progress.getSatisfiedMethods().contains(progress.getInProgressVerificationMethod())) {
                 progress.setInProgressVerificationMethod(null);

+ 36 - 13
pwm/servlet/src/password/pwm/http/servlet/NewUserServlet.java

@@ -381,25 +381,43 @@ public class NewUserServlet extends PwmServlet {
             final TokenPayload tokenPayload = pwmApplication.getTokenService().processUserEnteredCode(
                     pwmSession,
                     null,
-                    newUserBean.getVerificationPhase().getTokenName(),
+                    null,
                     userEnteredCode
             );
             if (tokenPayload != null) {
                 final NewUserTokenData newUserTokenData = NewUserFormUtils.fromTokenPayload(pwmRequest, tokenPayload);
                 newUserBean.setProfileID(newUserTokenData.profileID);
-                final NewUserBean.NewUserForm newUserForm = newUserTokenData.formData;
-                if (newUserBean.getVerificationPhase() == NewUserBean.NewUserVerificationPhase.EMAIL) {
-                    LOGGER.debug("Email token passed");
+                final NewUserBean.NewUserForm newUserFormFromToken = newUserTokenData.formData;
+                if (NewUserBean.NewUserVerificationPhase.EMAIL.getTokenName().equals(tokenPayload.getName())) {
+                    LOGGER.debug(pwmRequest, "email token passed");
+
+                    try {
+                        verifyForm(pwmRequest, newUserFormFromToken);
+                    } catch (PwmUnrecoverableException | PwmOperationalException e) {
+                        LOGGER.error(pwmRequest,"while reading stored form data in token payload, form validation error occured: " + e.getMessage());
+                        throw e;
+                    }
+
+                    newUserBean.setNewUserForm(newUserFormFromToken);
+                    newUserBean.setFormPassed(true);
                     newUserBean.setEmailTokenPassed(true);
                     newUserBean.setVerificationPhase(NewUserBean.NewUserVerificationPhase.NONE);
                     tokenPassed = true;
-                } else if (newUserBean.getVerificationPhase() == NewUserBean.NewUserVerificationPhase.SMS) {
-                    LOGGER.debug("SMS token passed");
-                    newUserBean.setSmsTokenPassed(true);
-                    newUserBean.setVerificationPhase(NewUserBean.NewUserVerificationPhase.NONE);
-                    tokenPassed = true;
+                } else if (NewUserBean.NewUserVerificationPhase.SMS.getTokenName().equals(tokenPayload.getName())) {
+                    if (newUserBean.getNewUserForm() != null && newUserBean.getNewUserForm().isConsistentWith(newUserFormFromToken)) {
+                        LOGGER.debug(pwmRequest, "SMS token passed");
+                        newUserBean.setSmsTokenPassed(true);
+                        newUserBean.setVerificationPhase(NewUserBean.NewUserVerificationPhase.NONE);
+                        tokenPassed = true;
+                    } else {
+                        LOGGER.debug(pwmRequest, "SMS token value is valid, but form data does not match current session form data");
+                        final String errorMsg = "sms token does not match current session";
+                        errorInformation = new ErrorInformation(PwmError.ERROR_TOKEN_INCORRECT,errorMsg);
+                    }
+                } else {
+                    final String errorMsg = "token name/type is not recognized: " + tokenPayload.getName();
+                    errorInformation = new ErrorInformation(PwmError.ERROR_TOKEN_INCORRECT,errorMsg);
                 }
-                newUserBean.setNewUserForm(newUserForm);
             }
         } catch (PwmOperationalException e) {
             final String errorMsg = "token incorrect: " + e.getMessage();
@@ -425,7 +443,7 @@ public class NewUserServlet extends PwmServlet {
         final Set<String> profileIDs = pwmRequest.getConfig().getNewUserProfiles().keySet();
         final String requestedProfileID = pwmRequest.readParameterAsString("profile");
         
-        if ("-".equalsIgnoreCase(requestedProfileID)) {
+        if (requestedProfileID == null || requestedProfileID.isEmpty()) {
             newUserBean.setProfileID(null);
         } if (profileIDs.contains(requestedProfileID)) {
             newUserBean.setProfileID(requestedProfileID);
@@ -1077,12 +1095,17 @@ public class NewUserServlet extends PwmServlet {
                 throws PwmOperationalException, PwmUnrecoverableException
         {
             final Locale userLocale = pwmRequest.getLocale();
-            final List<FormConfiguration> newUserFormDefinition = getFormDefinition(pwmRequest);
 
             final Map<String, String> payloadMap = tokenPayload.getData();
             final String profileID = payloadMap.get(TOKEN_PAYLOAD_ATTR);
             payloadMap.remove(TOKEN_PAYLOAD_ATTR);
-            
+
+            final NewUserProfile newUserProfile = pwmRequest.getConfig().getNewUserProfiles().get(profileID);
+            if (newUserProfile == null) {
+                throw new PwmOperationalException(PwmError.ERROR_TOKEN_INCORRECT,"token data references an invalid new user profileID");
+            }
+
+            final List<FormConfiguration> newUserFormDefinition = newUserProfile.readSettingAsForm(PwmSetting.NEWUSER_FORM);
             final Map<FormConfiguration, String> userFormValues = FormUtility.readFormValuesFromMap(payloadMap,
                     newUserFormDefinition, userLocale);
             final PasswordData passwordData;

+ 2 - 2
pwm/servlet/src/password/pwm/http/servlet/ShortcutServlet.java

@@ -3,7 +3,7 @@
  * http://code.google.com/p/pwm/
  *
  * Copyright (c) 2006-2009 Novell, Inc.
- * Copyright (c) 2009-2014 The PWM Project
+ * Copyright (c) 2009-2015 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
@@ -50,7 +50,7 @@ public class ShortcutServlet extends PwmServlet {
 
         public Collection<PwmServlet.HttpMethod> permittedMethods()
         {
-            return Collections.singletonList(PwmServlet.HttpMethod.POST);
+            return Collections.singletonList(PwmServlet.HttpMethod.GET);
         }
     }
 

+ 71 - 0
pwm/servlet/src/password/pwm/http/tag/PwmScriptRefTag.java

@@ -0,0 +1,71 @@
+/*
+ * Password Management Servlets (PWM)
+ * http://code.google.com/p/pwm/
+ *
+ * Copyright (c) 2006-2009 Novell, Inc.
+ * Copyright (c) 2009-2015 The PWM Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package password.pwm.http.tag;
+
+import password.pwm.http.JspUtility;
+import password.pwm.http.PwmRequest;
+import password.pwm.util.logging.PwmLogger;
+
+import javax.servlet.jsp.tagext.TagSupport;
+import java.io.IOException;
+
+public class PwmScriptRefTag extends TagSupport {
+// --------------------- Interface Tag ---------------------
+
+    private static final PwmLogger LOGGER = PwmLogger.forClass(PwmScriptRefTag.class);
+
+    private String url;
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public int doEndTag()
+            throws javax.servlet.jsp.JspTagException
+    {
+        try {
+            final PwmRequest pwmRequest = JspUtility.getPwmRequest(pageContext);
+            final String cspNonce = pwmRequest.getCspNonce();
+
+            String url = getUrl();
+            url = PwmUrlTag.insertContext(pageContext,url);
+            url = PwmUrlTag.insertResourceNonce(pwmRequest.getPwmApplication(), url);
+
+            final String output = "<script type=\"text/javascript\" nonce=\"" + cspNonce + "\" src=\"" + url + "\"></script>";
+            pageContext.getOut().write(output);
+        } catch (Exception e) {
+            try {
+                pageContext.getOut().write("error-generating-script-ref-tag");
+            } catch (IOException e1) {
+                /* ignore */
+            }
+            LOGGER.error("error during scriptRef output of pwmFormID: " + e.getMessage());
+        }
+        return EVAL_PAGE;
+    }
+
+}

+ 11 - 2
pwm/servlet/src/password/pwm/http/tag/PwmUrlTag.java

@@ -118,12 +118,21 @@ public class PwmUrlTag extends PwmAbstractTag {
         return ServletHelper.appendAndEncodeUrlParameters(outputURL, Collections.singletonMap(PwmConstants.PARAM_FORM_ID,pwmFormID));
     }
 
-    private static String insertContext(final PageContext pageContext, final String urlString) {
+    static String insertContext(final PageContext pageContext, final String urlString) {
         final String contextPath = pageContext.getServletContext().getContextPath();
         if (!urlString.startsWith("/")) {
             return urlString;
         }
 
+        if (
+                urlString.toLowerCase().startsWith("http://")
+                        || urlString.toLowerCase().startsWith("https://")
+                        || urlString.startsWith("//")
+                )
+        {
+            return urlString;
+        }
+
         if (urlString.startsWith(contextPath)) {
             return urlString;
         }
@@ -132,7 +141,7 @@ public class PwmUrlTag extends PwmAbstractTag {
 
     }
 
-    private static String insertResourceNonce(final PwmApplication pwmApplication, final String urlString) {
+    static String insertResourceNonce(final PwmApplication pwmApplication, final String urlString) {
         if (pwmApplication != null && urlString.contains(RESOURCE_URL)) {
             final String nonce = ResourceFileServlet.makeResourcePathNonce(pwmApplication);
             if (nonce != null && nonce.length() > 0) {

+ 1 - 1
pwm/servlet/src/password/pwm/i18n/Admin.properties

@@ -22,7 +22,7 @@
 
 # Strings found in "admin" viewable sections of the application
 
-Header_AdminUser=You are logged in as administrator.
+Header_AdminUser=%1%  You are logged in as administrator.
 Header_ConfigModeActive=%1% is in open configuration mode and is not secure.
 Header_TrialMode=%1% Trial.
 IntruderRecordType_ADDRESS=Address

+ 258 - 0
pwm/servlet/src/password/pwm/i18n/LocaleHelper.java

@@ -25,9 +25,21 @@ package password.pwm.i18n;
 import password.pwm.PwmApplication;
 import password.pwm.PwmConstants;
 import password.pwm.config.Configuration;
+import password.pwm.config.PwmSetting;
+import password.pwm.config.StoredValue;
+import password.pwm.config.value.ChallengeValue;
+import password.pwm.config.value.StringArrayValue;
+import password.pwm.cr.ChallengeItemBean;
+import password.pwm.error.PwmException;
+import password.pwm.error.PwmOperationalException;
+import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.PwmRequest;
+import password.pwm.util.Percent;
+import password.pwm.util.StringUtil;
 import password.pwm.util.logging.PwmLogger;
 
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.*;
 
 public class LocaleHelper {
@@ -251,4 +263,250 @@ public class LocaleHelper {
         Display key = input ? Display.Value_True : Display.Value_False;
         return Display.getLocalizedMessage(locale, key, configuration);
     }
+
+    static public class LocaleStats {
+        List<Locale> localesExamined = new ArrayList<>();
+        int totalKeys;
+        int presentSlots;
+        int missingSlots;
+        int totalSlots;
+        String totalPercentage;
+        Map<Locale,String> perLocale_percentLocalizations = new LinkedHashMap<>();
+        Map<Locale,Integer> perLocale_presentLocalizations = new LinkedHashMap<>();
+        Map<Locale,Integer> perLocale_missingLocalizations = new LinkedHashMap<>();
+        Map<PwmLocaleBundle,Map<Locale,List<String>>> missingKeys = new LinkedHashMap<>();
+
+        public List<Locale> getLocalesExamined() {
+            return localesExamined;
+        }
+
+        public int getTotalKeys() {
+            return totalKeys;
+        }
+
+        public String getTotalPercentage() {
+            return totalPercentage;
+        }
+
+        public int getPresentSlots() {
+            return presentSlots;
+        }
+
+        public int getMissingSlots() {
+            return missingSlots;
+        }
+
+        public int getTotalSlots() {
+            return totalSlots;
+        }
+
+        public Map<Locale, String> getPerLocale_percentLocalizations() {
+            return perLocale_percentLocalizations;
+        }
+
+        public Map<Locale, Integer> getPerLocale_presentLocalizations() {
+            return perLocale_presentLocalizations;
+        }
+
+        public Map<Locale, Integer> getPerLocale_missingLocalizations() {
+            return perLocale_missingLocalizations;
+        }
+
+        public Map<PwmLocaleBundle, Map<Locale, List<String>>> getMissingKeys() {
+            return missingKeys;
+        }
+    }
+
+    static public class ConfigLocaleStats {
+        List<Locale> defaultChallenges = new ArrayList<>();
+        Map<Locale,String> description_percentLocalizations = new LinkedHashMap<>();
+        Map<Locale,Integer> description_presentLocalizations = new LinkedHashMap<>();
+        Map<Locale,Integer> description_missingLocalizations = new LinkedHashMap<>();
+
+        public List<Locale> getDefaultChallenges() {
+            return defaultChallenges;
+        }
+
+        public Map<Locale, String> getDescription_percentLocalizations() {
+            return description_percentLocalizations;
+        }
+
+        public Map<Locale, Integer> getDescription_presentLocalizations() {
+            return description_presentLocalizations;
+        }
+
+        public Map<Locale, Integer> getDescription_missingLocalizations() {
+            return description_missingLocalizations;
+        }
+    }
+
+    public static ConfigLocaleStats getConfigLocaleStats() throws PwmUnrecoverableException, PwmOperationalException {
+
+        final ConfigLocaleStats configLocaleStats = new ConfigLocaleStats();
+        {
+            final StoredValue storedValue = PwmSetting.CHALLENGE_RANDOM_CHALLENGES.getDefaultValue(PwmSetting.Template.DEFAULT);
+            Map<String, List<ChallengeItemBean>> value = ((ChallengeValue) storedValue).toNativeObject();
+
+            for (String localeStr : value.keySet()) {
+                final Locale loopLocale = LocaleHelper.parseLocaleString(localeStr);
+                configLocaleStats.getDefaultChallenges().add(loopLocale);
+            }
+        }
+
+        for (final Locale locale : LocaleInfoGenerator.knownLocales()) {
+            configLocaleStats.description_presentLocalizations.put(locale,0);
+            configLocaleStats.description_missingLocalizations.put(locale,0);
+        }
+
+        for (final PwmSetting pwmSetting : PwmSetting.values()) {
+            final String defaultValue = pwmSetting.getDescription(PwmConstants.DEFAULT_LOCALE);
+            configLocaleStats.description_presentLocalizations.put(PwmConstants.DEFAULT_LOCALE, configLocaleStats.description_presentLocalizations.get(PwmConstants.DEFAULT_LOCALE) + 1);
+            for (final Locale locale : LocaleInfoGenerator.knownLocales()) {
+                if (!PwmConstants.DEFAULT_LOCALE.equals(locale)) {
+                    final String localeValue = pwmSetting.getDescription(locale);
+                    if (defaultValue.equals(localeValue)) {
+                        configLocaleStats.description_missingLocalizations.put(PwmConstants.DEFAULT_LOCALE, configLocaleStats.description_missingLocalizations.get(locale) + 1);
+                    } else {
+                        configLocaleStats.description_presentLocalizations.put(PwmConstants.DEFAULT_LOCALE, configLocaleStats.description_presentLocalizations.get(locale) + 1);
+                    }
+                }
+            }
+        }
+
+        for (final Locale locale : LocaleInfoGenerator.knownLocales()) {
+            final int totalCount = PwmSetting.values().length;
+            final int presentCount = configLocaleStats.getDescription_presentLocalizations().get(locale);
+            final Percent percent = new Percent(presentCount, totalCount);
+            configLocaleStats.getDescription_percentLocalizations().put(locale, percent.pretty());
+        }
+            return configLocaleStats;
+    }
+
+    public static LocaleStats getStatsForBundles(final Collection<PwmLocaleBundle> bundles) {
+        final LocaleStats stats = new LocaleStats();
+        LocaleInfoGenerator.checkLocalesOnBundle(stats,bundles);
+        return stats;
+    }
+
+    private static class LocaleInfoGenerator {
+        private static final boolean debugFlag = false;
+
+        private static void checkLocalesOnBundle(
+                final LocaleStats stats,
+                final Collection<PwmLocaleBundle> bundles
+        ) {
+            for (final PwmLocaleBundle pwmLocaleBundle : bundles) {
+                final Map<Locale,List<String>> missingKeys = checkLocalesOnBundle(pwmLocaleBundle, stats);
+                stats.missingKeys.put(pwmLocaleBundle, missingKeys);
+            }
+
+            stats.getLocalesExamined().addAll(knownLocales());
+
+            if (stats.getTotalSlots() > 0) {
+                Percent percent = new Percent(stats.getPresentSlots(),stats.getTotalSlots());
+                stats.totalPercentage = percent.pretty();
+            } else {
+                stats.totalPercentage = Percent.ZERO.pretty();
+            }
+        }
+
+
+        private static Map<Locale,List<String>> checkLocalesOnBundle(
+                final PwmLocaleBundle pwmLocaleBundle,
+                final LocaleStats stats
+        ) {
+            final Map<Locale, List<String>> returnMap = new LinkedHashMap<>();
+            final int keyCount = pwmLocaleBundle.getKeys().size();
+            stats.totalKeys += keyCount;
+
+            for (final Locale locale : knownLocales()) {
+                final List<String> missingKeys = missingKeysForBundleAndLocale(pwmLocaleBundle, locale);
+                final int missingKeyCount = missingKeys.size();
+                final int presentKeyCount = keyCount - missingKeyCount;
+
+                stats.totalSlots += keyCount;
+                stats.missingSlots += missingKeyCount;
+                stats.presentSlots += presentKeyCount;
+                if (!stats.perLocale_missingLocalizations.containsKey(locale)) {
+                    stats.perLocale_missingLocalizations.put(locale,0);
+                }
+                stats.perLocale_missingLocalizations.put(locale, stats.getPerLocale_missingLocalizations().get(locale) + missingKeyCount);
+                if (!stats.perLocale_presentLocalizations.containsKey(locale)) {
+                    stats.perLocale_presentLocalizations.put(locale,0);
+                }
+                stats.perLocale_presentLocalizations.put(locale, stats.perLocale_presentLocalizations.get(locale) + presentKeyCount);
+
+                if (keyCount > 0) {
+                    Percent percent = new Percent(presentKeyCount, keyCount);
+                    stats.perLocale_percentLocalizations.put(locale, percent.pretty(0));
+                } else {
+                    stats.perLocale_percentLocalizations.put(locale, Percent.ZERO.pretty());
+                }
+
+                returnMap.put(locale, missingKeys);
+            }
+            return returnMap;
+        }
+
+        private static List<String> missingKeysForBundleAndLocale(
+                final PwmLocaleBundle pwmLocaleBundle,
+                final Locale locale
+        )
+        {
+            final List<String> returnList = new ArrayList<>();
+
+            final String bundleFilename = PwmConstants.DEFAULT_LOCALE.equals(locale)
+                    ? pwmLocaleBundle.getTheClass().getSimpleName() + ".properties"
+                    : pwmLocaleBundle.getTheClass().getSimpleName() + "_" + locale.toString() + ".properties";
+            final Properties checkProperties = new Properties();
+
+            try {
+                final InputStream stream = pwmLocaleBundle.getTheClass().getResourceAsStream(bundleFilename);
+                if (stream == null) {
+                    if (debugFlag) {
+                        LOGGER.trace("missing resource bundle: bundle=" + pwmLocaleBundle.getTheClass().getName() + ", locale=" + locale.toString());
+                    }
+                    returnList.addAll(pwmLocaleBundle.getKeys());
+                } else {
+                    LOGGER.trace("checking file " + bundleFilename);
+                    checkProperties.load(stream);
+                    for (final String key : pwmLocaleBundle.getKeys()) {
+                        if (!checkProperties.containsKey(key)) {
+                            if (debugFlag) {
+                                LOGGER.trace("missing resource: bundle=" + pwmLocaleBundle.getTheClass().toString() + ", locale=" + locale.toString() + "' key=" + key);
+                            }
+                            returnList.add(key);
+                        }
+                    }
+                }
+            } catch (IOException e) {
+                if (debugFlag) {
+                    LOGGER.trace("error loading resource bundle for class='" + pwmLocaleBundle.getTheClass().toString() + ", locale=" + locale.toString() + "', error: " + e.getMessage());
+                }
+            }
+            Collections.sort(returnList);
+            return returnList;
+        }
+
+        private static List<Locale> knownLocales() {
+            final List<Locale> knownLocales = new ArrayList();
+            try {
+                final StringArrayValue stringArrayValue = (StringArrayValue) PwmSetting.KNOWN_LOCALES.getDefaultValue(PwmSetting.Template.DEFAULT);
+                final List<String> rawValues = stringArrayValue.toNativeObject();
+                final Map<String,String> localeFlagMap = StringUtil.convertStringListToNameValuePair(rawValues, "::");
+                for (final String rawValue : localeFlagMap.keySet()) {
+                    knownLocales.add(LocaleHelper.parseLocaleString(rawValue));
+                }
+            } catch (PwmException e) {
+                throw new IllegalStateException("error reading default locale list",e);
+            }
+
+            final Map<String,Locale> returnMap = new TreeMap<>();
+
+            for (final Locale locale : knownLocales) {
+                returnMap.put(locale.getDisplayName(), locale);
+            }
+            return new ArrayList<>(returnMap.values());
+        }
+    }
 }

+ 77 - 0
pwm/servlet/src/password/pwm/i18n/PwmLocaleBundle.java

@@ -0,0 +1,77 @@
+/*
+ * Password Management Servlets (PWM)
+ * http://code.google.com/p/pwm/
+ *
+ * Copyright (c) 2006-2009 Novell, Inc.
+ * Copyright (c) 2009-2015 The PWM Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package password.pwm.i18n;
+
+import password.pwm.PwmConstants;
+
+import java.util.*;
+
+public enum PwmLocaleBundle {
+    DISPLAY(Display.class, false),
+    ERRORS(Error.class, false),
+    MESSAGE(Message.class, false),
+
+    CONFIG(Config.class, true),
+    ADMIN(Admin.class, true),
+    HEALTH(Health.class, true),
+    ;
+
+    private final Class theClass;
+    private final boolean adminOnly;
+    private Set<String> keys = null;
+
+    PwmLocaleBundle(final Class theClass, final boolean adminOnly) {
+        this.theClass = theClass;
+        this.adminOnly = adminOnly;
+    }
+
+    public Class getTheClass() {
+        return theClass;
+    }
+
+    public boolean isAdminOnly() {
+        return adminOnly;
+    }
+
+    public Set<String> getKeys() {
+        if (keys == null) {
+            final ResourceBundle defaultBundle = ResourceBundle.getBundle(this.getTheClass().getName(), PwmConstants.DEFAULT_LOCALE);
+            keys = Collections.unmodifiableSet(new HashSet<>(defaultBundle.keySet()));
+        }
+        return keys;
+    }
+
+    public static Collection<PwmLocaleBundle> allValues() {
+        return Collections.unmodifiableList(Arrays.asList(PwmLocaleBundle.values()));
+    }
+
+    public static Collection<PwmLocaleBundle> userFacingValues() {
+        final List<PwmLocaleBundle> returnValue = new ArrayList<>(allValues());
+        for (Iterator<PwmLocaleBundle> iter = returnValue.iterator(); iter.hasNext(); ) {
+            if (iter.next().isAdminOnly()) {
+                iter.remove();
+            }
+        }
+        return Collections.unmodifiableList(returnValue);
+    }
+}

+ 1 - 14
pwm/servlet/src/password/pwm/ldap/auth/AuthenticationRequest.java

@@ -201,20 +201,7 @@ class AuthenticationRequest {
             }
         } else {
             // verify user is not account disabled
-            final ChaiProvider proxyChaiProvider = pwmApplication.getProxyChaiProvider(
-                    userIdentity.getLdapProfileID());
-            final ChaiUser theUser = ChaiFactory.createChaiUser(userIdentity.getUserDN(), proxyChaiProvider);
-            try {
-                if (!theUser.isAccountEnabled()) {
-                    final String errorMsg = "prohibiting authentication via proxy user due to disabled LDAP account status";
-                    log(PwmLogLevel.DEBUG, errorMsg);
-                    throw new PwmOperationalException(new ErrorInformation(PwmError.ERROR_WRONGPASSWORD,errorMsg));
-                }
-            } catch (ChaiOperationException e) {
-                final String errorMsg = "error checking disabled LDAP account status during authentication via proxy user: " + e.getMessage();
-                log(PwmLogLevel.ERROR, errorMsg);
-                throw new PwmOperationalException(new ErrorInformation(PwmError.ERROR_UNKNOWN,errorMsg));
-            }
+            AuthenticationUtility.checkIfUserEligibleToAuthentication(pwmApplication, userIdentity);
         }
 
         statisticsManager.incrementValue(Statistic.AUTHENTICATIONS);

+ 63 - 0
pwm/servlet/src/password/pwm/ldap/auth/AuthenticationUtility.java

@@ -0,0 +1,63 @@
+/*
+ * Password Management Servlets (PWM)
+ * http://code.google.com/p/pwm/
+ *
+ * Copyright (c) 2006-2009 Novell, Inc.
+ * Copyright (c) 2009-2015 The PWM Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package password.pwm.ldap.auth;
+
+import com.novell.ldapchai.ChaiUser;
+import com.novell.ldapchai.exception.ChaiOperationException;
+import com.novell.ldapchai.exception.ChaiUnavailableException;
+import password.pwm.PwmApplication;
+import password.pwm.bean.UserIdentity;
+import password.pwm.error.PwmError;
+import password.pwm.error.PwmUnrecoverableException;
+
+public abstract class AuthenticationUtility {
+    public static void checkIfUserEligibleToAuthentication(
+            final PwmApplication pwmApplication,
+            final UserIdentity userIdentity
+    )
+            throws PwmUnrecoverableException
+    {
+        try {
+            checkIfUserEligibleToAuthenticationImpl(pwmApplication, userIdentity);
+        } catch (ChaiOperationException | ChaiUnavailableException e) {
+            throw new PwmUnrecoverableException(PwmError.forChaiError(e.getErrorCode()));
+        }
+    }
+
+    private static void checkIfUserEligibleToAuthenticationImpl(
+            final PwmApplication pwmApplication,
+            final UserIdentity userIdentity
+    )
+            throws PwmUnrecoverableException, ChaiUnavailableException, ChaiOperationException
+    {
+        final ChaiUser chaiUser = pwmApplication.getProxiedChaiUser(userIdentity);
+
+        if (!chaiUser.isAccountEnabled()) {
+            throw new PwmUnrecoverableException(PwmError.ERROR_ACCOUNT_DISABLED);
+        }
+
+        if (chaiUser.isAccountExpired()) {
+            throw new PwmUnrecoverableException(PwmError.ERROR_ACCOUNT_EXPIRED);
+        }
+    }
+}

+ 0 - 157
pwm/servlet/src/password/pwm/util/CodeIntegrityChecker.java

@@ -26,17 +26,12 @@ import password.pwm.AppProperty;
 import password.pwm.PwmConstants;
 import password.pwm.config.Configuration;
 import password.pwm.config.PwmSetting;
-import password.pwm.config.value.StringArrayValue;
 import password.pwm.error.PwmError;
-import password.pwm.error.PwmException;
 import password.pwm.health.HealthMessage;
-import password.pwm.i18n.LocaleHelper;
 import password.pwm.i18n.Message;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.ws.server.rest.bean.HealthRecord;
 
-import java.io.IOException;
-import java.io.InputStream;
 import java.lang.reflect.Method;
 import java.util.*;
 
@@ -44,26 +39,6 @@ public class CodeIntegrityChecker {
     final static private PwmLogger LOGGER = PwmLogger.forClass(CodeIntegrityChecker.class);
     final static private boolean debugFlag = false;
 
-    static public class Stats {
-        Set<String> examinedResourceBundles = new TreeSet<>();
-        int totalLocales;
-        int totalLocaleKeys;
-        int presentLocalizations;
-        int missingLocalizations;
-        int totalLocalizationSlots;
-        Map<String,String> perLocale_percentLocalizations = new TreeMap<>();
-        Map<String,Integer> perLocale_presentLocalizations = new TreeMap<>();
-        Map<String,Integer> perLocale_missingLocalizations = new TreeMap<>();
-    }
-
-    private static final List<Class> LOCALE_CHECK_CLASSES = new ArrayList<>(Arrays.asList(new Class[] {
-            //password.pwm.i18n.Admin.class,
-            //password.pwm.i18n.Config.class,
-            password.pwm.i18n.Display.class,
-            password.pwm.i18n.Error.class,
-            //password.pwm.i18n.Health.class,
-            password.pwm.i18n.Message.class,
-    }));
 
     private static final Map<Method,Object[]> CHECK_ENUM_METHODS = new LinkedHashMap<>();
     static {
@@ -97,19 +72,11 @@ public class CodeIntegrityChecker {
     }
 
     public Set<password.pwm.health.HealthRecord> checkResources() {
-        Stats stats = new Stats();
         final Set<password.pwm.health.HealthRecord> returnSet = new TreeSet<>();
         returnSet.addAll(checkEnumMethods());
-        returnSet.addAll(checkLocalesOnBundle(stats));
         return returnSet;
     }
 
-    public Stats getStats() {
-        final Stats stats = new Stats();
-        checkLocalesOnBundle(stats);
-        return stats;
-    }
-
     private Set<password.pwm.health.HealthRecord> checkEnumMethods() {
         final Set<password.pwm.health.HealthRecord> returnSet = new LinkedHashSet<>();
         for (final Method method : CHECK_ENUM_METHODS.keySet()) {
@@ -150,128 +117,12 @@ public class CodeIntegrityChecker {
         return returnRecords;
     }
 
-    private Set<password.pwm.health.HealthRecord> checkLocalesOnBundle(
-            final Stats stats
-    ) {
-        final Set<password.pwm.health.HealthRecord> returnSet = new LinkedHashSet<>();
-        stats.totalLocales = knownLocales().size();
-        for (final Class loopClass : LOCALE_CHECK_CLASSES) {
-            final Map<Locale,List<String>> missingKeys = checkLocalesOnBundle(loopClass,stats);
-            for (final Locale locale : missingKeys.keySet()) {
-                for (final String key : missingKeys.get(locale)) {
-                    returnSet.add(password.pwm.health.HealthRecord.forMessage(
-                            HealthMessage.MissingResource,
-                            loopClass.getName(),
-                            locale.toString() + " " + locale.getDisplayName(),
-                            key
-                    ));
-                }
-            }
-        }
-        return returnSet;
-    }
-
-    private Map<Locale,String> knownLocales() {
-
-        final List<Locale> knownLocales = new ArrayList();
-        try {
-            final StringArrayValue stringArrayValue = (StringArrayValue)PwmSetting.KNOWN_LOCALES.getDefaultValue(PwmSetting.Template.DEFAULT);
-            final List<String> rawValues = stringArrayValue.toNativeObject();
-            final Map<String,String> localeFlagMap = StringUtil.convertStringListToNameValuePair(rawValues, "::");
-            for (final String rawValue : localeFlagMap.keySet()) {
-                knownLocales.add(LocaleHelper.parseLocaleString(rawValue));
-            }
-        } catch (PwmException e) {
-            throw new IllegalStateException("error reading default locale list",e);
-        }
-
-        final Map<Locale,String> returnMap = new LinkedHashMap<>();
-
-        Collections.sort(knownLocales,new Comparator<Locale>() {
-            public int compare(Locale o1, Locale o2) {
-                return o1.toString().compareTo(o2.toString());
-            }
-        });
-        for (final Locale locale : knownLocales) {
-            final String descr = locale.toString() + " - " + locale.getDisplayLanguage();
-            returnMap.put(locale,descr);
-        }
-        return returnMap;
-    }
-
-    private Map<Locale,List<String>> checkLocalesOnBundle(
-            final Class checkClass,
-            final Stats stats
-    ) {
-        final Map<Locale,List<String>> returnMap = new LinkedHashMap<>();
-        final ResourceBundle defaultLocaleBundle = ResourceBundle.getBundle(checkClass.getName());
-
-        stats.totalLocaleKeys += defaultLocaleBundle.keySet().size();
-        stats.examinedResourceBundles.add(checkClass.toString());
-        for (final Locale locale : knownLocales().keySet()) {
-            final String localeDescr = knownLocales().get(locale);
-            if (!stats.perLocale_missingLocalizations.containsKey(localeDescr)) {
-                stats.perLocale_missingLocalizations.put(localeDescr,0);
-            }
-            if (!stats.perLocale_presentLocalizations.containsKey(localeDescr)) {
-                stats.perLocale_presentLocalizations.put(localeDescr, 0);
-            }
-            final String bundleFilename = PwmConstants.DEFAULT_LOCALE.equals(locale)
-                    ? checkClass.getSimpleName() + ".properties"
-                    : checkClass.getSimpleName() + "_" + locale.toString() + ".properties";
-            final Properties checkProperties = new Properties();
-            try {
-                final InputStream stream = checkClass.getResourceAsStream(bundleFilename);
-                if (stream == null) {
-                    if (debugFlag) {
-                        LOGGER.trace("missing resource bundle: bundle=" + checkClass.getName() + ", locale=" + locale.toString());
-                    }
-                } else {
-                    LOGGER.trace("checking file " + bundleFilename);
-                    checkProperties.load(stream);
-                    final List<String> returnList = new ArrayList<>();
-                    for (final String key : defaultLocaleBundle.keySet()) {
-                        stats.totalLocalizationSlots++;
-                        if (!checkProperties.containsKey(key)) {
-                            if (debugFlag) {
-                                LOGGER.trace("missing resource: bundle=" + checkClass.toString() + ", locale=" + locale.toString() + "' key=" + key);
-                            }
-                            returnList.add(key);
-                            stats.missingLocalizations++;
-                            stats.perLocale_missingLocalizations.put(localeDescr,stats.perLocale_missingLocalizations.get(localeDescr) + 1);
-                        } else {
-                            stats.presentLocalizations++;
-                            stats.perLocale_presentLocalizations.put(localeDescr,stats.perLocale_presentLocalizations.get(localeDescr) + 1);
-                        }
-                    }
-                    Collections.sort(returnList);
-                    returnMap.put(locale,Collections.unmodifiableList(returnList));
-                }
-            } catch (IOException e) {
-                if (debugFlag) {
-                    LOGGER.trace("error loading resource bundle for class='" + checkClass.toString() + ", locale=" + locale.toString() + "', error: " + e.getMessage());
-                }
-            }
-        }
-        for (final Locale locale : knownLocales().keySet()) {
-            final String localeDescr = knownLocales().get(locale);
-            if (stats.perLocale_missingLocalizations.containsKey(localeDescr)
-                    && stats.perLocale_presentLocalizations.containsKey(localeDescr)) {
-                int total = stats.perLocale_missingLocalizations.get(localeDescr) + stats.perLocale_presentLocalizations.get(localeDescr);
-                Percent percent = new Percent(stats.perLocale_presentLocalizations.get(localeDescr),total);
-                stats.perLocale_percentLocalizations.put(localeDescr,percent.pretty(0));
-            }
-
-        }
-        return returnMap;
-    }
 
     public String asPrettyJsonOutput() {
         final Map<String,Object> outputMap = new LinkedHashMap<>();
         outputMap.put("information",
                 PwmConstants.PWM_APP_NAME + " " + PwmConstants.SERVLET_VERSION + " IntegrityCheck " + PwmConstants.DEFAULT_DATETIME_FORMAT.format(
                         new Date()));
-        outputMap.put("localeInformation", this.getStats());
         {
             final Set<HealthRecord> healthBeans = new LinkedHashSet<>();
             for (final password.pwm.health.HealthRecord record : this.checkEnumMethods()) {
@@ -280,14 +131,6 @@ public class CodeIntegrityChecker {
             }
             outputMap.put("enumMethodHealthChecks", healthBeans);
         }
-        {
-            final Set<HealthRecord> healthBeans = new LinkedHashSet<>();
-            for (final password.pwm.health.HealthRecord record : this.checkLocalesOnBundle(new Stats())) {
-                healthBeans.add(
-                        HealthRecord.fromHealthRecord(record, PwmConstants.DEFAULT_LOCALE, null));
-            }
-            outputMap.put("localeHealthChecks", healthBeans);
-        }
         return JsonUtil.serializeMap(outputMap, JsonUtil.Flag.PrettyPrint);
     }
 }

+ 11 - 0
pwm/servlet/src/password/pwm/util/SecureHelper.java

@@ -264,6 +264,17 @@ public class SecureHelper {
         return hash(new ByteArrayInputStream(input), algorithm);
     }
 
+    public static String hash(
+            final String input
+    )
+            throws PwmUnrecoverableException
+    {
+        if (input == null || input.length() < 1) {
+            return null;
+        }
+        return hash(new ByteArrayInputStream(input.getBytes(PwmConstants.DEFAULT_CHARSET)), DEFAULT_HASH_ALGORITHM);
+    }
+
     public static String hash(
             final String input,
             final HashAlgorithm algorithm

+ 78 - 9
pwm/servlet/src/password/pwm/util/operations/ActionExecutor.java

@@ -3,7 +3,7 @@
  * http://code.google.com/p/pwm/
  *
  * Copyright (c) 2006-2009 Novell, Inc.
- * Copyright (c) 2009-2014 The PWM Project
+ * Copyright (c) 2009-2015 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
@@ -23,6 +23,7 @@
 package password.pwm.util.operations;
 
 import com.novell.ldapchai.ChaiUser;
+import com.novell.ldapchai.exception.ChaiOperationException;
 import com.novell.ldapchai.exception.ChaiUnavailableException;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
@@ -46,9 +47,7 @@ import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroMachine;
 
 import java.net.URI;
-import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 
 public class ActionExecutor {
 
@@ -97,17 +96,16 @@ public class ActionExecutor {
     {
         final String attributeName = actionConfiguration.getAttributeName();
         final String attributeValue = actionConfiguration.getAttributeValue();
-        final Map<String,String> attributeMap = Collections.singletonMap(attributeName,attributeValue);
         final ChaiUser theUser = settings.getChaiUser() != null ?
                 settings.getChaiUser() :
                 pwmApplication.getProxiedChaiUser(settings.getUserIdentity());
 
-
-        Helper.writeMapToLdap(
+        writeLdapAttribute(
                 theUser,
-                attributeMap,
-                settings.getMacroMachine(),
-                settings.isExpandPwmMacros()
+                attributeName,
+                attributeValue,
+                actionConfiguration.getLdapMethod(),
+                settings.getMacroMachine()
         );
     }
 
@@ -186,6 +184,77 @@ public class ActionExecutor {
         }
     }
 
+    private static void writeLdapAttribute(
+            final ChaiUser theUser,
+            final String attrName,
+            String attrValue,
+            ActionConfiguration.LdapMethod ldapMethod,
+            final MacroMachine macroMachine
+    )
+            throws PwmOperationalException, ChaiUnavailableException
+    {
+        if (ldapMethod == null) {
+            ldapMethod = ActionConfiguration.LdapMethod.replace;
+        }
+
+        if (macroMachine != null) {
+            attrValue  = macroMachine.expandMacros(attrValue);
+        }
+
+        LOGGER.trace("beginning ldap " + ldapMethod.toString() + " operation on " + theUser.getEntryDN() + ", attribute " + attrName);
+        switch (ldapMethod) {
+            case replace:
+            {
+                try {
+                    theUser.writeStringAttribute(attrName, attrValue);
+                    LOGGER.info("replaced attribute on user " + theUser.getEntryDN() + " (" + attrName + "=" + attrValue + ")");
+                } catch (ChaiOperationException e) {
+                    final String errorMsg = "error setting '" + attrName + "' attribute on user " + theUser.getEntryDN() + ", error: " + e.getMessage();
+                    final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_UNKNOWN, errorMsg);
+                    final PwmOperationalException newException = new PwmOperationalException(errorInformation);
+                    newException.initCause(e);
+                    throw newException;
+                }
+            }
+            break;
+
+            case add:
+            {
+                try {
+                    theUser.addAttribute(attrName, attrValue);
+                    LOGGER.info("added attribute on user " + theUser.getEntryDN() + " (" + attrName + "=" + attrValue + ")");
+                } catch (ChaiOperationException e) {
+                    final String errorMsg = "error adding '" + attrName + "' attribute value from user " + theUser.getEntryDN() + ", error: " + e.getMessage();
+                    final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_UNKNOWN, errorMsg);
+                    final PwmOperationalException newException = new PwmOperationalException(errorInformation);
+                    newException.initCause(e);
+                    throw newException;
+                }
+
+            }
+            break;
+
+            case remove:
+            {
+                try {
+                    theUser.deleteAttribute(attrName, attrValue);
+                    LOGGER.info("deleted attribute value on user " + theUser.getEntryDN() + " (" + attrName + ")");
+                } catch (ChaiOperationException e) {
+                    final String errorMsg = "error deletig '" + attrName + "' attribute value on user " + theUser.getEntryDN() + ", error: " + e.getMessage();
+                    final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_UNKNOWN, errorMsg);
+                    final PwmOperationalException newException = new PwmOperationalException(errorInformation);
+                    newException.initCause(e);
+                    throw newException;
+                }
+            }
+            break;
+
+            default:
+                throw new IllegalStateException("unexpected ldap method type " + ldapMethod);
+        }
+    }
+
+
 
     public static class ActionExecutorSettings {
         private MacroMachine macroMachine;

+ 35 - 6
pwm/servlet/src/password/pwm/util/operations/CrService.java

@@ -23,14 +23,13 @@
 package password.pwm.util.operations;
 
 import com.novell.ldapchai.ChaiUser;
-import com.novell.ldapchai.cr.Challenge;
-import com.novell.ldapchai.cr.ChallengeSet;
-import com.novell.ldapchai.cr.ResponseSet;
+import com.novell.ldapchai.cr.*;
 import com.novell.ldapchai.exception.ChaiException;
 import com.novell.ldapchai.exception.ChaiUnavailableException;
 import com.novell.ldapchai.exception.ChaiValidationException;
 import com.novell.ldapchai.impl.edir.NmasCrFactory;
 import com.novell.ldapchai.provider.ChaiProvider;
+import password.pwm.AppProperty;
 import password.pwm.PwmApplication;
 import password.pwm.PwmService;
 import password.pwm.bean.ResponseInfoBean;
@@ -130,14 +129,14 @@ public class CrService implements PwmService {
                         final ChallengeProfile challengeProfile = ChallengeProfile.createChallengeProfile(
                                 challengeID,
                                 locale,
-                                returnSet,
+                                applyPwmPolicyToNmasChallenges(returnSet, config),
                                 null,
-                                0,
+                                Integer.parseInt(config.readAppProperty(AppProperty.NMAS_CR_MIN_RANDOM_DURING_SETUP)),
                                 0
                         );
 
                         LOGGER.debug(sessionLabel,"using ldap c/r policy for user " + theUser.getEntryDN() + ": " + returnSet.toString());
-                        LOGGER.trace(sessionLabel,"readUserChallengeProfile completed in " + TimeDuration.fromCurrent(methodStartTime).asCompactString());
+                        LOGGER.trace(sessionLabel,"readUserChallengeProfile completed in " + TimeDuration.fromCurrent(methodStartTime).asCompactString() + ", result=" + JsonUtil.serialize(challengeProfile));
 
                         return challengeProfile;
                     }
@@ -154,9 +153,39 @@ public class CrService implements PwmService {
         LOGGER.debug(sessionLabel,"no detected c/r policy for user " + theUser.getEntryDN() + " in ldap ");
         LOGGER.trace(sessionLabel,"readUserChallengeProfile completed in " + TimeDuration.fromCurrent(methodStartTime).asCompactString());
         return challengeProfile;
+    }
+
+    private static ChallengeSet applyPwmPolicyToNmasChallenges(final ChallengeSet challengeSet, final Configuration configuration) throws PwmUnrecoverableException {
+        final List<Challenge> newChallenges = new ArrayList<>();
+        final boolean applyWordlist = Boolean.parseBoolean(configuration.readAppProperty(AppProperty.NMAS_CR_APPLY_WORDLIST));
+        final int questionsInAnswer = Integer.parseInt(configuration.readAppProperty(AppProperty.NMAS_CR_MAX_QUESTION_CHARS_IN__ANSWER));
+        for (final Challenge challenge : challengeSet.getChallenges()) {
+            newChallenges.add(new ChaiChallenge(
+                    challenge.isRequired(),
+                    challenge.getChallengeText(),
+                    challenge.getMinLength(),
+                    challenge.getMaxLength(),
+                    challenge.isAdminDefined(),
+                    questionsInAnswer,
+                    applyWordlist
+            ));
+        }
 
+        try {
+            return new ChaiChallengeSet(
+                    newChallenges,
+                    challengeSet.getMinRandomRequired(),
+                    challengeSet.getLocale(),
+                    challengeSet.getIdentifier()
+            );
+        } catch (ChaiValidationException e) {
+            final String errorMsg = "unexpected error applying policies to nmas challengeset: " + e.getMessage();
+            LOGGER.error(errorMsg,e);
+            throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_UNKNOWN,errorMsg));
+        }
     }
 
+
     protected static String determineChallengeProfileForUser(
             final PwmApplication pwmApplication,
             final SessionLabel sessionLabel,

+ 1 - 1
pwm/servlet/src/password/pwm/util/stats/StatisticsManager.java

@@ -471,7 +471,7 @@ public class StatisticsManager implements PwmService {
             }
             final Configuration config = pwmApplication.getConfig();
             final List<String> configuredSettings = new ArrayList<>();
-            for (final PwmSetting pwmSetting : PwmSetting.values()) {
+            for (final PwmSetting pwmSetting : config.nonDefaultSettings()) {
                 if (!config.isDefaultValue(pwmSetting)) {
                     configuredSettings.add(pwmSetting.getKey());
                 }

+ 1 - 1
pwm/servlet/src/password/pwm/ws/server/RestServerHelper.java

@@ -57,7 +57,7 @@ public abstract class RestServerHelper {
     private static final PwmLogger LOGGER = PwmLogger.forClass(RestServerHelper.class);
 
     public static javax.ws.rs.core.Response doHtmlRedirect() throws URISyntaxException {
-        final URI uri = javax.ws.rs.core.UriBuilder.fromUri("../rest.jsp?forwardedFromRestServer=true").build();
+        final URI uri = javax.ws.rs.core.UriBuilder.fromUri("../reference/rest.jsp?forwardedFromRestServer=true").build();
         return javax.ws.rs.core.Response.temporaryRedirect(uri).build();
     }
 

+ 1 - 1
pwm/servlet/src/password/pwm/ws/server/rest/RestCheckPasswordServer.java

@@ -91,7 +91,7 @@ public class RestCheckPasswordServer extends AbstractRestServer {
     @GET
     @Produces(MediaType.TEXT_HTML)
     public javax.ws.rs.core.Response doHtmlRedirect() throws URISyntaxException {
-        final URI uri = javax.ws.rs.core.UriBuilder.fromUri("../rest.jsp?forwardedFromRestServer=true").build();
+        final URI uri = javax.ws.rs.core.UriBuilder.fromUri("../reference/rest.jsp?forwardedFromRestServer=true").build();
         return javax.ws.rs.core.Response.temporaryRedirect(uri).build();
     }
 

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/admin-activity.jsp

@@ -39,7 +39,7 @@
 <html dir="<pwm:LocaleOrientation/>">
 <%@ include file="/WEB-INF/jsp/fragment/header.jsp" %>
 <body class="nihilo">
-<style>
+<style nonce="<pwm:value name="cspNonce"/>" type="text/css">
     .analysisGrid {
         min-height: 55vh;
     }

+ 2 - 2
pwm/servlet/web/WEB-INF/jsp/admin-analysis.jsp

@@ -128,7 +128,7 @@
                         <tr><td><pwm:display key="Display_PleaseWait"/></td></tr>
                     </table>
                     <table style="width:450px;">
-                        <tr><td style="text-align: center; text-decoration: no-underline; cursor: pointer">
+                        <tr><td style="text-align: center; cursor: pointer">
                             <button id="reportStartButton" class="btn">
                                 <pwm:if test="showIcons"><span class="btn-icon fa fa-play">&nbsp;</span></pwm:if>
                                 <pwm:display key="Button_Report_Start" bundle="Admin"/>
@@ -161,7 +161,7 @@
                                 <td colspan="10" style="text-align: center">
                                     <form action="<pwm:url url='Administration'/>" method="GET" enctype="application/x-www-form-urlencoded"
                                           name="statsUpdateForm" id="statsUpdateForm">
-                                        <select name="statsPeriodSelect""
+                                        <select name="statsPeriodSelect"
                                                 style="width: 500px;" data-dojo-props="maxHeight: -1">
                                             <option value="<%=StatisticsManager.KEY_CUMULATIVE%>" <%= StatisticsManager.KEY_CUMULATIVE.equals(statsPeriodSelect) ? "selected=\"selected\"" : "" %>>
                                                 since installation - <%= dateFormat.format(analysis_pwmRequest.getPwmApplication().getInstallTime()) %>

+ 19 - 23
pwm/servlet/web/WEB-INF/jsp/admin-dashboard.jsp

@@ -307,7 +307,7 @@
                                 License Information
                             </td>
                             <td>
-                                <a href="<pwm:context/><pwm:url url="/public/license.jsp"/>">License Information</a>
+                                <a href="<pwm:context/><pwm:url url="/public/reference/license.jsp"/>">License Information</a>
                             </td>
                         </tr>
                     </table>
@@ -425,8 +425,8 @@
                                 Log Events in Write Queue
                             </td>
                             <td>
-                                <%= dashboard_pwmApplication.getLocalDBLogger() != null 
-                                        ? numberFormat.format(dashboard_pwmApplication.getLocalDBLogger().getPendingEventCount()) 
+                                <%= dashboard_pwmApplication.getLocalDBLogger() != null
+                                        ? numberFormat.format(dashboard_pwmApplication.getLocalDBLogger().getPendingEventCount())
                                         : JspUtility.getMessage(pageContext, Display.Value_NotApplicable) %>
                             </td>
                         </tr>
@@ -447,9 +447,9 @@
                                 Oldest Log Event in Write Queue
                             </td>
                             <td>
-                                <%= dashboard_pwmApplication.getLocalDBLogger() != null 
-                                        ? dashboard_pwmApplication.getLocalDBLogger().getDirtyQueueTime().asCompactString() 
-                                        : JspUtility.getMessage(pageContext, Display.Value_NotApplicable) 
+                                <%= dashboard_pwmApplication.getLocalDBLogger() != null
+                                        ? dashboard_pwmApplication.getLocalDBLogger().getDirtyQueueTime().asCompactString()
+                                        : JspUtility.getMessage(pageContext, Display.Value_NotApplicable)
                                 %>
                             </td>
                         </tr>
@@ -458,8 +458,8 @@
                                 Oldest Log Event in LocalDB
                             </td>
                             <td>
-                                <%= dashboard_pwmApplication.getLocalDBLogger() != null 
-                                        ? TimeDuration.fromCurrent(dashboard_pwmApplication.getLocalDBLogger().getTailDate()).asCompactString() 
+                                <%= dashboard_pwmApplication.getLocalDBLogger() != null
+                                        ? TimeDuration.fromCurrent(dashboard_pwmApplication.getLocalDBLogger().getTailDate()).asCompactString()
                                         : JspUtility.getMessage(pageContext, Display.Value_NotApplicable)
                                 %>
                             </td>
@@ -506,9 +506,9 @@
                                 LocalDB Free Space
                             </td>
                             <td>
-                                <%= dashboard_pwmApplication.getLocalDB() == null 
+                                <%= dashboard_pwmApplication.getLocalDB() == null
                                         ? JspUtility.getMessage(pageContext, Display.Value_NotApplicable)
-                                        : dashboard_pwmApplication.getLocalDB().getFileLocation() == null 
+                                        : dashboard_pwmApplication.getLocalDB().getFileLocation() == null
                                         ? JspUtility.getMessage(pageContext, Display.Value_NotApplicable)
                                         : Helper.formatDiskSize(Helper.diskSpaceRemaining(dashboard_pwmApplication.getLocalDB().getFileLocation())) %>
                             </td>
@@ -754,25 +754,21 @@
 <pwm:script>
     <script type="text/javascript">
         PWM_GLOBAL['startupFunctions'].push(function(){
-            require(["dojo/parser","dojo/ready","dijit/layout/TabContainer","dijit/layout/ContentPane","dijit/Dialog","dojo/domReady!"],function(dojoParser,ready){
-                ready(function(){
-                    dojoParser.parse();
-                    ready(function(){
-                        PWM_ADMIN.showStatChart('PASSWORD_CHANGES',14,'statsChart',{refreshTime:11*1000});
-                        PWM_ADMIN.showAppHealth('healthBody', {showRefresh:true,showTimestamp:true});
+            require(["dojo/parser","dijit/layout/TabContainer","dijit/layout/ContentPane"],function(dojoParser){
+                dojoParser.parse();
+                PWM_ADMIN.showStatChart('PASSWORD_CHANGES',14,'statsChart',{refreshTime:11*1000});
+                PWM_ADMIN.showAppHealth('healthBody', {showRefresh:true,showTimestamp:true});
 
-                        PWM_MAIN.addEventHandler('button-showLocalDBCounts','click',function(){
-                            PWM_MAIN.showWaitDialog({loadFunction:function(){
-                                PWM_MAIN.goto('Administration?showLocalDBCounts=true');
-                            }})
-                        });
-                    });
+                PWM_MAIN.addEventHandler('button-showLocalDBCounts','click',function(){
+                    PWM_MAIN.showWaitDialog({loadFunction:function(){
+                        PWM_MAIN.goto('Administration?showLocalDBCounts=true');
+                    }})
                 });
             });
         });
     </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/admin.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/admin.js"/>
 <%@ include file="/WEB-INF/jsp/fragment/footer.jsp" %>
 </body>
 </html>

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/admin-logview-window.jsp

@@ -81,7 +81,7 @@
     <% } %></pre>
 <% } %>
 <%@ include file="/WEB-INF/jsp/fragment/footer.jsp" %>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configmanager.js"/>"></script>
+<pwm:script-ref url="/public/resources/js/configmanager.js"/>
 <pwm:script>
 <script type="text/javascript">
     PWM_GLOBAL['startupFunctions'].push(function(){

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/admin-logview.jsp

@@ -250,7 +250,7 @@
                 };
             </script>
         </pwm:script>
-        <style scoped="scoped">
+        <style nonce="<pwm:value name="cspNonce"/>" scoped="scoped">
             .dgrid { height: auto; }
             .dgrid .dgrid-scroller { position: relative;  overflow: visible; }
             .dgrid-column-timestamp {width: 80px;}

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/admin-tokenlookup.jsp

@@ -160,7 +160,7 @@
         </table>
         <br/>
         <% } %>
-        <form id="tokenForm" action="admin-tokenlookup.jsp" method="post">
+        <form id="tokenForm" action="Administration" method="post">
             <textarea name="token" id="token" style="width: 580px; height: 150px"></textarea>
             <div class="buttonbar">
                 <input name="submitBtn" class="btn" type="submit" value="Lookup Token"/>

+ 5 - 22
pwm/servlet/web/WEB-INF/jsp/captcha.jsp

@@ -1,6 +1,4 @@
-<%@ page import="password.pwm.error.PwmException" %>
-<%@ page import="password.pwm.util.stats.Statistic" %>
-<%@ page import="password.pwm.util.stats.StatisticsManager" %>
+<%@ page import="password.pwm.util.StringUtil" %>
 <%--
   ~ Password Management Servlets (PWM)
   ~ http://code.google.com/p/pwm/
@@ -31,30 +29,15 @@
 <%@ include file="fragment/header.jsp" %>
 <body class="nihilo">
 <%-- begin reCaptcha section (http://code.google.com/apis/recaptcha/docs/display.html) --%>
-<%
-    String reCaptchaPublicKey = "";
-    String reCaptchaProtocol = "";
-    Locale locale = PwmConstants.DEFAULT_LOCALE;
-    try {
-        reCaptchaProtocol = request.isSecure() ? "https" : "http";
-        final PwmRequest pwmRequest = PwmRequest.forRequest(request,response);
-        reCaptchaPublicKey = pwmRequest.getConfig().readSettingAsString(PwmSetting.RECAPTCHA_KEY_PUBLIC);
-        locale = pwmRequest.getLocale();
-        StatisticsManager.incrementStat(pwmRequest,Statistic.CAPTCHA_PRESENTATIONS);
-    } catch (PwmException e) {
-        /* noop */
-    }
-%>
-
-<script type="text/javascript" src="<%=reCaptchaProtocol%>://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
+<pwm:script-ref url="<%=(String)JspUtility.getAttribute(pageContext,PwmConstants.REQUEST_ATTR.CaptchaClientUrl)%>"/>
 <pwm:script>
     <script type="text/javascript">
         PWM_GLOBAL['startupFunctions'].push(function(){
-            Recaptcha.create("<%=reCaptchaPublicKey%>",
+            Recaptcha.create("<%=StringUtil.escapeJS((String)JspUtility.getAttribute(pageContext,PwmConstants.REQUEST_ATTR.CaptchaPublicKey))%>",
                     "recaptcha_widget",
                     {
                         theme: "custom",
-                        lang: '<%=locale%>',
+                        lang: '<%=JspUtility.getPwmRequest(pageContext).getLocale()%>',
                         callback: Recaptcha.focus_response_field
                     }
             );
@@ -103,7 +86,7 @@
                 </div>
             </div>
             <noscript>
-                <iframe src="<%=reCaptchaProtocol%>://www.google.com/recaptcha/api/noscript?k=<%=reCaptchaPublicKey%>&hl=<%=locale%>"
+                <iframe nonce="<pwm:value name="cspNonce"/>" src="<%=JspUtility.getAttribute(pageContext,PwmConstants.REQUEST_ATTR.CaptchaIframeUrl)%>"
                         height="300" width="500" frameborder="0"></iframe>
                 <br>
                 <textarea name="recaptcha_challenge_field" rows="3" cols="40">

+ 2 - 3
pwm/servlet/web/WEB-INF/jsp/changepassword-wait.jsp

@@ -1,12 +1,11 @@
 <%@ page import="password.pwm.error.PwmException" %>
-<%@ page import="password.pwm.http.JspUtility" %>
 <%@ page import="java.util.Date" %>
 <%--
   ~ Password Management Servlets (PWM)
   ~ http://code.google.com/p/pwm/
   ~
   ~ Copyright (c) 2006-2009 Novell, Inc.
-  ~ Copyright (c) 2009-2014 The PWM Project
+  ~ Copyright (c) 2009-2015 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
@@ -79,7 +78,7 @@
     });
 </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/changepassword.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/changepassword.js"/>
 <% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_FOOTER_TEXT);%>
 <%@ include file="/WEB-INF/jsp/fragment/footer.jsp" %>
 </body>

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/changepassword.jsp

@@ -120,7 +120,7 @@
     });
 </script>
 </pwm:script>
-<script nonce="<pwm:value name="cspNonce"/>" type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/changepassword.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/changepassword.js"/>
 <%@ include file="fragment/footer.jsp" %>
 </body>
 </html>

+ 8 - 8
pwm/servlet/web/WEB-INF/jsp/configeditor.jsp

@@ -37,7 +37,7 @@
 <% final boolean configUnlocked = configeditor_pwmRequest.getPwmApplication().getApplicationMode() == PwmApplication.MODE.CONFIGURATION && !PwmConstants.TRIAL_MODE; %>
 <% final String configNotes = configManagerBean.getStoredConfiguration().readConfigProperty(StoredConfiguration.ConfigProperty.PROPERTY_KEY_NOTES);%>
 <body class="nihilo">
-<style>
+<style nonce="<pwm:value name="cspNonce"/>" type="text/css">
     html { overflow-y: scroll; } <%-- always add verticle scrollbar to page --%>
 </style>
 <link href="<pwm:context/><pwm:url url='/public/resources/configStyle.css'/>" rel="stylesheet" type="text/css"/>
@@ -47,9 +47,6 @@
             <div id="header-title">
                 <%=PwmConstants.PWM_APP_NAME%> Configuration Editor <span id="currentPageDisplay"></span>
                 <span style="visibility: hidden" id="working_icon" class="headerIcon fa fa-cog fa-spin"></span>
-                <span id="idle_status" class="editorIdleStatus">
-                    <%--idle timeout text --%>
-                </span>
                 <div class="headerIcon" id="cancelButton_icon">
                     <span class="fa fa-times"></span>
                 </div>
@@ -65,6 +62,9 @@
                 <div class="headerIcon" id="macroDoc_icon">
                     <span class="fa fa-magic"></span>
                 </div>
+                <span id="idle_status" class="editorIdleStatus">
+                    <%--idle timeout text --%>
+                </span>
             </div>
         </div>
     </div>
@@ -151,10 +151,10 @@
 </pwm:script>
 <% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_LOCALE); %>
 <% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_FOOTER_TEXT); %>
-<script nonce="<pwm:value name="cspNonce"/>" type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configmanager.js"/>"></script>
-<script nonce="<pwm:value name="cspNonce"/>" type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configeditor.js"/>"></script>
-<script nonce="<pwm:value name="cspNonce"/>" type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configeditor-settings.js"/>"></script>
-<script nonce="<pwm:value name="cspNonce"/>" type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/admin.js"/>"></script>
+<pwm:script-ref url="/public/resources/js/configmanager.js"/>
+<pwm:script-ref url="/public/resources/js/configeditor.js"/>
+<pwm:script-ref url="/public/resources/js/configeditor-settings.js"/>
+<pwm:script-ref url="/public/resources/js/admin.js"/>
 <%@ include file="fragment/footer.jsp" %>
 </body>
 </html>

+ 3 - 3
pwm/servlet/web/WEB-INF/jsp/configguide-app.jsp

@@ -100,9 +100,9 @@
 </script>
 </pwm:script>
 <% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_LOCALE); %>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configguide.js"/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configmanager.js"/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/admin.js"/>"></script>
+<pwm:script-ref url="/public/resources/js/configguide.js"/>
+<pwm:script-ref url="/public/resources/js/configmanager.js"/>
+<pwm:script-ref url="/public/resources/js/admin.js"/>
 <%@ include file="fragment/footer.jsp" %>
 </body>
 </html>

+ 3 - 3
pwm/servlet/web/WEB-INF/jsp/configguide-cr_storage.jsp

@@ -108,9 +108,9 @@
 </script>
 </pwm:script>
 <% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_LOCALE); %>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configguide.js"/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configmanager.js"/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/admin.js"/>"></script>
+<pwm:script-ref url="/public/resources/js/configguide.js"/>
+<pwm:script-ref url="/public/resources/js/configmanager.js"/>
+<pwm:script-ref url="/public/resources/js/admin.js"/>
 <%@ include file="fragment/footer.jsp" %>
 </body>
 </html>

+ 3 - 3
pwm/servlet/web/WEB-INF/jsp/configguide-end.jsp

@@ -180,9 +180,9 @@
     </script>
 </pwm:script>
 <% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_LOCALE); %>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configguide.js"/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configmanager.js"/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/admin.js"/>"></script>
+<pwm:script-ref url="/public/resources/js/configguide.js"/>
+<pwm:script-ref url="/public/resources/js/configmanager.js"/>
+<pwm:script-ref url="/public/resources/js/admin.js"/>
 <%@ include file="fragment/footer.jsp" %>
 </body>
 </html>

+ 3 - 3
pwm/servlet/web/WEB-INF/jsp/configguide-ldap.jsp

@@ -279,9 +279,9 @@
         }
     </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configguide.js"/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configmanager.js"/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/admin.js"/>"></script>
+<pwm:script-ref url="/public/resources/js/configguide.js"/>
+<pwm:script-ref url="/public/resources/js/configmanager.js"/>
+<pwm:script-ref url="/public/resources/js/admin.js"/>
 <% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_LOCALE); %>
 <%@ include file="fragment/footer.jsp" %>
 </body>

+ 3 - 3
pwm/servlet/web/WEB-INF/jsp/configguide-ldap2.jsp

@@ -172,9 +172,9 @@
 </script>
 </pwm:script>
 <% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_LOCALE); %>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configguide.js"/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configmanager.js"/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/admin.js"/>"></script>
+<pwm:script-ref url="/public/resources/js/configguide.js"/>
+<pwm:script-ref url="/public/resources/js/configmanager.js"/>
+<pwm:script-ref url="/public/resources/js/admin.js"/>
 <%@ include file="fragment/footer.jsp" %>
 </body>
 </html>

+ 3 - 3
pwm/servlet/web/WEB-INF/jsp/configguide-ldap3.jsp

@@ -142,9 +142,9 @@
 </script>
 </pwm:script>
 <% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_LOCALE); %>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configguide.js"/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configmanager.js"/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/admin.js"/>"></script>
+<pwm:script-ref url="/public/resources/js/configguide.js"/>
+<pwm:script-ref url="/public/resources/js/configmanager.js"/>
+<pwm:script-ref url="/public/resources/js/admin.js"/>
 <%@ include file="fragment/footer.jsp" %>
 </body>
 </html>

+ 3 - 2
pwm/servlet/web/WEB-INF/jsp/configguide-ldap_schema.jsp

@@ -124,8 +124,9 @@
         });
     </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configguide.js"/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configmanager.js"/>"></script>
+<pwm:script-ref url="/public/resources/js/configguide.js"/>
+<pwm:script-ref url="/public/resources/js/configmanager.js"/>
+<pwm:script-ref url="/public/resources/js/admin.js"/>
 <% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_LOCALE);%>
 <%@ include file="fragment/footer.jsp" %>
 </body>

+ 4 - 3
pwm/servlet/web/WEB-INF/jsp/configguide-ldapcert.jsp

@@ -64,7 +64,7 @@
                 </div>
                 <div class="setting_body">
                     The following are the LDAP server certificates read from the server at
-                    <style></style><b><%=configGuideBean.getFormData().get(ConfigGuideServlet.PARAM_LDAP_HOST)%>:<%=configGuideBean.getFormData().get(ConfigGuideServlet.PARAM_LDAP_PORT)%></b>.
+                    <b><%=configGuideBean.getFormData().get(ConfigGuideServlet.PARAM_LDAP_HOST)%>:<%=configGuideBean.getFormData().get(ConfigGuideServlet.PARAM_LDAP_PORT)%></b>.
                     Please verify these certificates match your LDAP server.
                     <div>
                         <div id="titlePane_<%=ConfigGuideServlet.PARAM_LDAP_HOST%>" style="padding-left: 5px; padding-top: 5px">
@@ -183,8 +183,9 @@
     });
 </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configguide.js"/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configmanager.js"/>"></script>
+<pwm:script-ref url="/public/resources/js/configguide.js"/>
+<pwm:script-ref url="/public/resources/js/configmanager.js"/>
+<pwm:script-ref url="/public/resources/js/admin.js"/>
 <% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_LOCALE);%>
 <%@ include file="fragment/footer.jsp" %>
 </body>

+ 3 - 2
pwm/servlet/web/WEB-INF/jsp/configguide-password.jsp

@@ -162,8 +162,9 @@
     }
 </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configguide.js"/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configmanager.js"/>"></script>
+<pwm:script-ref url="/public/resources/js/configguide.js"/>
+<pwm:script-ref url="/public/resources/js/configmanager.js"/>
+<pwm:script-ref url="/public/resources/js/admin.js"/>
 <% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_LOCALE);%>
 <%@ include file="fragment/footer.jsp" %>
 </body>

+ 4 - 4
pwm/servlet/web/WEB-INF/jsp/configguide-start.jsp

@@ -1,10 +1,9 @@
-<%@ page import="password.pwm.http.JspUtility" %>
 <%--
   ~ Password Management Servlets (PWM)
   ~ http://code.google.com/p/pwm/
   ~
   ~ Copyright (c) 2006-2009 Novell, Inc.
-  ~ Copyright (c) 2009-2014 The PWM Project
+  ~ Copyright (c) 2009-2015 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
@@ -123,8 +122,9 @@
         }
     </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configguide.js"/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configmanager.js"/>"></script>
+<pwm:script-ref url="/public/resources/js/configguide.js"/>
+<pwm:script-ref url="/public/resources/js/configmanager.js"/>
+<pwm:script-ref url="/public/resources/js/admin.js"/>
 <% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_LOCALE); %>
 <%@ include file="fragment/footer.jsp" %>
 </body>

+ 3 - 3
pwm/servlet/web/WEB-INF/jsp/configguide-template.jsp

@@ -117,9 +117,9 @@
         });
     </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configguide.js"/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configmanager.js"/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/admin.js"/>"></script>
+<pwm:script-ref url="/public/resources/js/configguide.js"/>
+<pwm:script-ref url="/public/resources/js/configmanager.js"/>
+<pwm:script-ref url="/public/resources/js/admin.js"/>
 <% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_LOCALE);%>
 <%@ include file="fragment/footer.jsp" %>
 </body>

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/configmanager-login.jsp

@@ -35,7 +35,7 @@
 <html dir="<pwm:LocaleOrientation/>">
 <%@ include file="fragment/header.jsp" %>
 <body class="nihilo">
-<script nonce="<pwm:value name="cspNonce"/>" type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configmanager.js"/>"></script>
+<pwm:script-ref url="/public/resources/js/configmanager.js"/>
 <div id="wrapper" class="login-wrapper">
     <jsp:include page="fragment/header-body.jsp">
         <jsp:param name="pwm.PageName" value="<%=pageTitle%>"/>

+ 3 - 3
pwm/servlet/web/WEB-INF/jsp/configmanager.jsp

@@ -39,7 +39,7 @@
     </jsp:include>
     <div id="centerbody">
         <%@ include file="/WEB-INF/jsp/fragment/message.jsp" %>
-        <style>
+        <style nonce="<pwm:value name="cspNonce"/>">
             .buttoncell {
                 border: 0;
                 width:50%;
@@ -350,8 +350,8 @@
 
     </script>
 </pwm:script>
-<script nonce="<pwm:value name="cspNonce"/>" type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configmanager.js"/>"></script>
-<script nonce="<pwm:value name="cspNonce"/>" type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/admin.js"/>"></script>
+<pwm:script-ref url="/public/resources/js/configmanager.js"/>
+<pwm:script-ref url="/public/resources/js/admin.js"/>
 <div><%@ include file="fragment/footer.jsp" %></div>
 </body>
 </html>

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

@@ -82,7 +82,7 @@ this is handled this way so on browsers where hiding fields is not possible, the
         });
     </script>
 </pwm:script>
-<script nonce="<pwm:value name="cspNonce"/>" type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/responses.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/responses.js"/>
 <%@ include file="fragment/footer.jsp" %>
 </body>
 </html>

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

@@ -69,7 +69,7 @@ this is handled this way so on browsers where hiding fields is not possible, the
     </div>
     <div class="push"></div>
 </div>
-<script nonce="<pwm:value name="cspNonce"/>" type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/responses.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/responses.js"/>
 <%@ include file="fragment/footer.jsp" %>
 </body>
 </html>

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/fragment/admin-nav.jsp

@@ -27,7 +27,7 @@
     final AdminBean adminBean = PwmRequest.forRequest(request,response).getPwmSession().getSessionBean(AdminBean.class);
     final AdminServlet.Page currentPage = adminBean.getCurrentPage();
 %>
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/admin.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/admin.js"/>
 <pwm:script>
 <script type="text/javascript">
     var PWM_ADMIN = PWM_ADMIN || {};

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/fragment/footer.jsp

@@ -89,4 +89,4 @@
     </script>
 </pwm:script>
 <script nonce="<pwm:value name="cspNonce"/>" data-dojo-config="async: true" dojo-sync-loader="false" type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/dojo/dojo/dojo.js'/>"></script>
-<script nonce="<pwm:value name="cspNonce"/>" type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/main.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/main.js"/>

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/fragment/header-warnings.jsp

@@ -61,7 +61,7 @@
     }
 %>
 <% if (includeHeader) { %>
-<script nonce="<pwm:value name="cspNonce"/>" type="text/javascript" src="<pwm:context/><pwm:url url="/public/resources/js/configmanager.js"/>"></script>
+<pwm:script-ref url="/public/resources/js/configmanager.js"/>
 <pwm:script>
     <script type="text/javascript">
         PWM_GLOBAL['startupFunctions'].push(function(){

+ 2 - 2
pwm/servlet/web/WEB-INF/jsp/helpdesk-detail.jsp

@@ -758,8 +758,8 @@
         });
     </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/helpdesk.js'/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/changepassword.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/helpdesk.js"/>
+<pwm:script-ref url="/public/resources/js/changepassword.js"/>
 <jsp:include page="/WEB-INF/jsp/fragment/footer.jsp"/>
 </body>
 </html>

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/helpdesk.jsp

@@ -79,7 +79,7 @@
     });
 </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/helpdesk.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/helpdesk.js"/>
 <jsp:include page="/WEB-INF/jsp/fragment/footer.jsp"/>
 </body>
 </html>

+ 11 - 10
pwm/servlet/web/WEB-INF/jsp/newuser-entercode.jsp

@@ -1,4 +1,5 @@
 <%@ page import="password.pwm.http.bean.NewUserBean" %>
+<%@ page import="password.pwm.http.servlet.NewUserServlet" %>
 
 <%--
   ~ Password Management Servlets (PWM)
@@ -55,22 +56,22 @@
                 <%@ include file="/WEB-INF/jsp/fragment/button-reset.jsp" %>
                 <input type="hidden" id="processAction" name="processAction" value="enterCode"/>
                 <input type="hidden" id="pwmFormID" name="pwmFormID" value="<pwm:FormID/>"/>
-            </div>
-        </form>
-        <div style="text-align: center">
-            <form action="<pwm:url url='/public/NewUser' addContext="true"/>" method="post"
-                  enctype="application/x-www-form-urlencoded">
-                <input type="hidden" name="processAction" value="reset"/>
-                <button type="submit" name="button" class="btn" id="button_reset">
+                <button type="button" name="button-cancel" class="btn" id="button-cancel">
                     <pwm:if test="showIcons"><span class="btn-icon fa fa-times"></span></pwm:if>
                     <pwm:display key="Button_Cancel"/>
                 </button>
-                <input type="hidden" name="pwmFormID" value="<pwm:FormID/>"/>
-            </form>
-        </div>
+            </div>
+        </form>
     </div>
     <div class="push"></div>
 </div>
+<pwm:script>
+    <script>
+        PWM_GLOBAL['startupFunctions'].push(function(){
+            PWM_MAIN.submitPostAction('button-cancel','NewUser','<%=NewUserServlet.NewUserAction.reset%>');
+        });
+    </script>
+</pwm:script>
 <%@ include file="fragment/footer.jsp" %>
 </body>
 </html>

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/newuser-wait.jsp

@@ -74,7 +74,7 @@
     });
 </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/newuser.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/newuser.js"/>
 <% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_FOOTER_TEXT); %>
 <%@ include file="/WEB-INF/jsp/fragment/footer.jsp" %>
 </body>

+ 14 - 24
pwm/servlet/web/WEB-INF/jsp/newuser.jsp

@@ -51,45 +51,35 @@
                 </button>
                 <%@ include file="/WEB-INF/jsp/fragment/button-reset.jsp" %>
                 <input type="hidden" name="pwmFormID" value="<pwm:FormID/>"/>
-            </div>
-        </form>
-        <div class="buttonbar">
-            <% if (pwmRequest.getConfig().getNewUserProfiles().keySet().size() > 1) { %>
-            <form action="<pwm:url url='NewUser'/>" method="post" name="form-goback" enctype="application/x-www-form-urlencoded"
-                  id="form-goback" class="pwm-form">
-                <button type="submit" name="Create" class="btn">
+
+                <% if (pwmRequest.getConfig().getNewUserProfiles().keySet().size() > 1) { %>
+                <button type="button" id="button-goBack" name="button-goBack" class="btn" >
                     <pwm:if test="showIcons"><span class="btn-icon fa fa-backward"></span></pwm:if>
                     <pwm:display key="Button_GoBack"/>
                 </button>
-                <input type="hidden" name="profile" value="-"/>
-                <input type="hidden" name="processAction" value="<%=NewUserServlet.NewUserAction.profileChoice%>"/>
-                <input type="hidden" name="pwmFormID" value="<pwm:FormID/>"/>
-            </form>
-            <% } %>
-            <pwm:if test="showCancel">
-                <form action="<pwm:url url='NewUser'/>" method="post" enctype="application/x-www-form-urlencoded" name="search" class="pwm-form">
-                    <button class="btn" type="submit" name="submitBtn">
+                <% } %>
+                <pwm:if test="showCancel">
+                    <button  type="submit" id="button-cancel" name="button-cancel" class="btn">
                         <pwm:if test="showIcons"><span class="btn-icon fa fa-times"></span></pwm:if>
                         <pwm:display key="Button_Cancel"/>
                     </button>
-                    <input type="hidden" name="processAction" value="reset"/>
-                    <input type="hidden" name="pwmFormID" value="<pwm:FormID/>"/>
-                </form>
-            </pwm:if>
-        </div>
-
+                </pwm:if>
+            </div>
+        </form>
     </div>
     <div class="push"></div>
 </div>
 <pwm:script>
     <script>
         PWM_GLOBAL['startupFunctions'].push(function(){
-            PWM_MAIN.addEventHandler('newUserForm','input',function(){PWM_NEWUSER.validateNewUserForm()})
+            PWM_MAIN.addEventHandler('newUserForm','input',function(){PWM_NEWUSER.validateNewUserForm()});
+            PWM_MAIN.submitPostAction('button-goBack','NewUser','<%=NewUserServlet.NewUserAction.profileChoice%>');
+            PWM_MAIN.submitPostAction('button-cancel','NewUser','<%=NewUserServlet.NewUserAction.reset%>');
         });
     </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/newuser.js'/>"></script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/changepassword.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/newuser.js"/>
+<pwm:script-ref url="/public/resources/js/changepassword.js"/>
 <%@ include file="fragment/footer.jsp" %>
 </body>
 </html>

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/peoplesearch.jsp

@@ -93,7 +93,7 @@
         });
     </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/peoplesearch.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/peoplesearch.js"/>
 <%@ include file="fragment/footer.jsp" %>
 </body>
 </html>

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/setupotpsecret-existing.jsp

@@ -94,7 +94,7 @@
     });
 </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/otpsecret.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/otpsecret.js"/>
 <%@ include file="fragment/footer.jsp" %>
 </body>
 </html>

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/setupotpsecret-success.jsp

@@ -34,7 +34,7 @@
 <html dir="<pwm:LocaleOrientation/>">
 <%@ include file="fragment/header.jsp" %>
 <body class="nihilo">
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/responses.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/responses.js"/>
 <div id="wrapper">
     <jsp:include page="fragment/header-body.jsp">
         <jsp:param name="pwm.PageName" value="Title_SetupOtpSecret"/>

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/setupotpsecret-test.jsp

@@ -81,7 +81,7 @@ TODO: support HOTP
     });
 </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/otpsecret.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/otpsecret.js"/>
 <%@ include file="fragment/footer.jsp" %>
 </body>
 </html>

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/setupotpsecret.jsp

@@ -127,7 +127,7 @@
         });
     </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/responses.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/responses.js"/>
 <%@ include file="fragment/footer.jsp" %>
 </body>
 </html>

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/setupresponses-helpdesk.jsp

@@ -64,7 +64,7 @@
         });
     </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/responses.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/responses.js"/>
 <%@ include file="fragment/footer.jsp" %>
 </body>
 </html>

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/setupresponses.jsp

@@ -62,7 +62,7 @@
         });
     </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/responses.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/responses.js"/>
 <%@ include file="fragment/footer.jsp" %>
 </body>
 </html>

+ 3 - 11
pwm/servlet/web/WEB-INF/jsp/shortcut.jsp

@@ -3,7 +3,7 @@
   ~ http://code.google.com/p/pwm/
   ~
   ~ Copyright (c) 2006-2009 Novell, Inc.
-  ~ Copyright (c) 2009-2014 The PWM Project
+  ~ Copyright (c) 2009-2015 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
@@ -55,16 +55,8 @@
             <% for (final ShortcutItem item : shortcutItems.values()) { %>
             <tr style="border:0">
                 <td style="border:0; text-align: right; width:10%">
-                    <%
-                        String target = "";
-                        try {
-                            final PwmRequest pwmRequest = PwmRequest.forRequest(request, response);
-                            target = pwmRequest.getConfig().readSettingAsBoolean(PwmSetting.SHORTCUT_NEW_WINDOW) ? item.getLabel() : "";
-                        } catch (PwmException e) {
-                            /* noop */
-                        }
-                    %>
-                    <a class="menubutton" target="<%=target%>" href="<pwm:url url='/private/Shortcuts' addContext="true"/>?processAction=selectShortcut&link=<%= item.getLabel() %>">
+                    <% final boolean newWindow = JspUtility.getPwmRequest(pageContext).getConfig().readSettingAsBoolean(PwmSetting.SHORTCUT_NEW_WINDOW); %>
+                    <a class="menubutton" <%=newWindow?" target=\"" + item.getLabel() + "\" " : ""%> href="<pwm:url url='/private/Shortcuts' addContext="true"/>?processAction=selectShortcut&link=<%= item.getLabel() %>">
                         <%= item.getLabel() %>
                     </a>
                 </td>

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/updateprofile.jsp

@@ -61,7 +61,7 @@
     });
 </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/updateprofile.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/updateprofile.js"/>
 <%@ include file="fragment/footer.jsp" %>
 </body>
 </html>

+ 12 - 1
pwm/servlet/web/WEB-INF/pwm-taglib.tld

@@ -216,7 +216,18 @@
         <name>script</name>
         <tag-class>password.pwm.http.tag.PwmScriptTag</tag-class>
         <body-content>JSP</body-content>
-        <description>Offline script to callback js</description>
+        <description>Embedded Script Wrapper</description>
+    </tag>
+    <tag>
+        <name>script-ref</name>
+        <tag-class>password.pwm.http.tag.PwmScriptRefTag</tag-class>
+        <body-content>empty</body-content>
+        <description>External Script Reference</description>
+        <attribute>
+            <name>url</name>
+            <required>true</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
     </tag>
 </taglib>
 

+ 1 - 1
pwm/servlet/web/public/health.jsp

@@ -237,7 +237,7 @@
     });
 </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/admin.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/admin.js"/>
 <% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_FOOTER_TEXT); %>
 <%@ include file="/WEB-INF/jsp/fragment/footer.jsp" %>
 </body>

+ 2 - 2
pwm/servlet/web/public/randomgen.jsp

@@ -3,7 +3,7 @@
   ~ http://code.google.com/p/pwm/
   ~
   ~ Copyright (c) 2006-2009 Novell, Inc.
-  ~ Copyright (c) 2009-2014 The PWM Project
+  ~ Copyright (c) 2009-2015 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
@@ -87,7 +87,7 @@
     });
 </script>
 </pwm:script>
-<script type="text/javascript" src="<pwm:context/><pwm:url url='/public/resources/js/changepassword.js'/>"></script>
+<pwm:script-ref url="/public/resources/js/changepassword.js"/>
 <%@ include file="/WEB-INF/jsp/fragment/footer.jsp" %>
 </body>
 </html>

+ 26 - 26
pwm/servlet/web/public/license.jsp → pwm/servlet/web/public/reference/license.jsp

@@ -30,7 +30,7 @@
 <html dir="<pwm:LocaleOrientation/>">
 <%@ include file="/WEB-INF/jsp/fragment/header.jsp" %>
 <body class="nihilo">
-<style type="text/css">
+<style nonce="<pwm:value name="cspNonce"/>" type="text/css">
     <!--
     .licenseBlock {
         background-color: #F5F5F5;
@@ -42,7 +42,7 @@
     -->
 </style>
 <div id="wrapper">
-    <jsp:include page="../WEB-INF/jsp/fragment/header-body.jsp">
+    <jsp:include page="../../WEB-INF/jsp/fragment/header-body.jsp">
         <jsp:param name="pwm.PageName" value="Software License Reference"/>
     </jsp:include>
     <div id="centerbody">
@@ -52,7 +52,7 @@
             <a href="http://code.google.com/p/pwm">http://code.google.com/p/pwm</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/gpl-2_license.txt"/></pre>
+                <pre><jsp:include page="../license/gpl-2_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -61,7 +61,7 @@
             <a href="http://commons.apache.org/">http://commons.apache.org/</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/apache20_license.txt"/></pre>
+                <pre><jsp:include page="../license/apache20_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -70,7 +70,7 @@
             <a href="http://db.apache.org/derby/">http://db.apache.org/derby/</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/apache20_license.txt"/></pre>
+                <pre><jsp:include page="../license/apache20_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -79,7 +79,7 @@
             <a href="http://hc.apache.org/">http://hc.apache.org/</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/apache20_license.txt"/></pre>
+                <pre><jsp:include page="../license/apache20_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -88,7 +88,7 @@
             <a href="http://logging.apache.org/log4j/1.2/">http://logging.apache.org/log4j/1.2/</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/apache20_license.txt"/></pre>
+                <pre><jsp:include page="../license/apache20_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -97,7 +97,7 @@
             <a href="http://asm.ow2.org/">http://asm.ow2.org/</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/asm_license.txt"/></pre>
+                <pre><jsp:include page="../license/asm_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -106,7 +106,7 @@
             <a href="http://www.jasig.org/cas">http://www.jasig.org/cas</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/ja-sig_license.txt"/></pre>
+                <pre><jsp:include page="../license/ja-sig_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -115,7 +115,7 @@
             <a href="http://dojotoolkit.org/">http://dojotoolkit.org/</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/dojo_license.txt"/></pre>
+                <pre><jsp:include page="../license/dojo_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -124,7 +124,7 @@
             <a href="http://dojofoundation.org/packages/dgrid/">http://dojofoundation.org/packages/dgrid/</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/dgrid_license.txt"/></pre>
+                <pre><jsp:include page="../license/dgrid_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -133,7 +133,7 @@
             <a href="http://www.dspace.org/">http://www.dspace.org/</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/dspace_license.txt"/></pre>
+                <pre><jsp:include page="../license/dspace_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -142,10 +142,10 @@
             <a href="http://fortawesome.github.io/Font-Awesome/">http://fortawesome.github.io/Font-Awesome/</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/OFL.txt"/></pre>
+                <pre><jsp:include page="../license/OFL.txt"/></pre>
             </div>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/MIT.txt"/></pre>
+                <pre><jsp:include page="../license/MIT.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -154,7 +154,7 @@
             <a href="http://code.google.com/p/google-authenticator/">http://code.google.com/p/google-authenticator/</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/apache20_license.txt"/></pre>
+                <pre><jsp:include page="../license/apache20_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -163,7 +163,7 @@
             <a href="http://code.google.com/p/google-gson/">http://code.google.com/p/google-gson/</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/h2_license.txt"/></pre>
+                <pre><jsp:include page="../license/h2_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -172,7 +172,7 @@
             <a href="http://www.h2database.com">http://www.h2database.com</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/apache20_license.txt"/></pre>
+                <pre><jsp:include page="../license/apache20_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -181,7 +181,7 @@
             <a href="http://www.mindrot.org/projects/jBCrypt/">http://www.mindrot.org/projects/jBCrypt/</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/jbCrypt_license.txt"/></pre>
+                <pre><jsp:include page="../license/jbCrypt_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -190,7 +190,7 @@
             <a href="http://www.jdom.org/">http://www.jdom.org/</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/jdom_license.txt"/></pre>
+                <pre><jsp:include page="../license/jdom_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -199,7 +199,7 @@
             <a href="http://jersey.java.net/">http://jersey.java.net/</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/glassfish_license.txt"/></pre>
+                <pre><jsp:include page="../license/glassfish_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -208,7 +208,7 @@
             <a href="https://code.google.com/p/ldapchai/">https://code.google.com/p/ldapchai/</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/lgpl-3.0_license.txt"/></pre>
+                <pre><jsp:include page="../license/lgpl-3.0_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -219,7 +219,7 @@
             <a href="http://www.novell.com/developer/ndk/ldap_classes_for_java.html">http://www.novell.com/developer/ndk/ldap_classes_for_java.html</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/openldap_license.txt"/></pre>
+                <pre><jsp:include page="../license/openldap_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -228,7 +228,7 @@
             <a href="https://github.com/kenglxn/QRGen">https://github.com/kenglxn/QRGen</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/apache20_license.txt"/></pre>
+                <pre><jsp:include page="../license/apache20_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -237,7 +237,7 @@
             <a href="https://github.com/wg/scrypt">https://github.com/wg/scrypt</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/apache20_license.txt"/></pre>
+                <pre><jsp:include page="../license/apache20_license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -246,7 +246,7 @@
             <a href="http://www.syslog4j.org/">http://www.syslog4j.org/</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/lgpl-2.1-license.txt"/></pre>
+                <pre><jsp:include page="../license/lgpl-2.1-license.txt"/></pre>
             </div>
             <br/>
         </div>
@@ -255,7 +255,7 @@
             <a href="http://code.google.com/p/zxing/">http://code.google.com/p/zxing/</a>
             <br/><br/>
             <div style="width:580px" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'License',open: false">
-                <pre><jsp:include page="license/apache20_license.txt"/></pre>
+                <pre><jsp:include page="../license/apache20_license.txt"/></pre>
             </div>
             <br/>
         </div>

+ 413 - 0
pwm/servlet/web/public/reference/localeinfo.jsp

@@ -0,0 +1,413 @@
+<%@ page import="password.pwm.error.PwmException" %>
+<%@ page import="password.pwm.http.JspUtility" %>
+<%@ page import="password.pwm.i18n.LocaleHelper" %>
+<%@ page import="password.pwm.i18n.PwmLocaleBundle" %>
+<%@ page import="java.text.NumberFormat" %>
+<%@ page import="java.util.ArrayList" %>
+<%@ page import="java.util.Arrays" %>
+<%@ page import="java.util.List" %>
+<%--
+  ~ Password Management Servlets (PWM)
+  ~ http://code.google.com/p/pwm/
+  ~
+  ~ Copyright (c) 2006-2009 Novell, Inc.
+  ~ Copyright (c) 2009-2015 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
+  --%>
+
+<!DOCTYPE html>
+<% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_HEADER_WARNINGS); %>
+<% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_THEME); %>
+<% JspUtility.setFlag(pageContext, PwmRequest.Flag.NO_REQ_COUNTER); %>
+<% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_HEADER_BUTTONS); %>
+<%@ page language="java" session="true" isThreadSafe="true" contentType="text/html; charset=UTF-8" %>
+<%@ taglib uri="pwm" prefix="pwm" %>
+<%
+    final List<Locale> HIGHLIGHTED_LOCALES = Arrays.asList(new Locale[] {
+            LocaleHelper.parseLocaleString("en"),
+            LocaleHelper.parseLocaleString("fr"),
+            LocaleHelper.parseLocaleString("zh_tw"),
+            LocaleHelper.parseLocaleString("ge"),
+            LocaleHelper.parseLocaleString("ja"),
+            LocaleHelper.parseLocaleString("pt_BR"),
+            LocaleHelper.parseLocaleString("es"),
+            LocaleHelper.parseLocaleString("sv")
+    });
+
+    PwmRequest pwmRequest = null;
+    LocaleHelper.LocaleStats allStats = null;
+    LocaleHelper.LocaleStats userFacingStats = null;
+    LocaleHelper.LocaleStats adminFacingStats = null;
+    LocaleHelper.ConfigLocaleStats configLocaleStats = null;
+    try {
+        pwmRequest = PwmRequest.forRequest(request, response);
+        allStats = LocaleHelper.getStatsForBundles(PwmLocaleBundle.allValues());
+        userFacingStats = LocaleHelper.getStatsForBundles(PwmLocaleBundle.userFacingValues());
+        {
+            final List<PwmLocaleBundle> adminBundles = new ArrayList<PwmLocaleBundle>(PwmLocaleBundle.allValues());
+            adminBundles.removeAll(PwmLocaleBundle.userFacingValues());
+            adminFacingStats = LocaleHelper.getStatsForBundles(adminBundles);
+        }
+        configLocaleStats = LocaleHelper.getConfigLocaleStats();
+    } catch (PwmException e) {
+        JspUtility.logError(pageContext, "error during page setup: " + e.getMessage());
+    }
+%>
+<html dir="<pwm:LocaleOrientation/>">
+<%@ include file="/WEB-INF/jsp/fragment/header.jsp" %>
+<% final NumberFormat numberFormat = NumberFormat.getNumberInstance(); %>
+<body class="nihilo">
+<div id="wrapper">
+    <style nonce="<pwm:value name="cspNonce"/>" >
+        .highlight {
+            background-color: rgba(255, 255, 0, 0.22);
+        }
+    </style>
+    <jsp:include page="/WEB-INF/jsp/fragment/header-body.jsp">
+        <jsp:param name="pwm.PageName" value="Localization Report"/>
+    </jsp:include>
+    <div id="centerbody">
+        <h1><a id="localeKeys">Localization Bundles</a></h1>
+        <table>
+            <tr>
+                <td class="title">
+                    Name
+                </td>
+                <td class="title">
+                    End User Facing
+                </td>
+                <td class="title">
+                    Keys
+                </td>
+                <td class="title">
+                    Strings
+                </td>
+            </tr>
+            <% for (final PwmLocaleBundle pwmLocaleBundle : PwmLocaleBundle.values()) { %>
+            <tr>
+                <td>
+                    <%=pwmLocaleBundle.getTheClass().getSimpleName()%>
+                </td>
+                <td>
+                    <%=LocaleHelper.booleanString(!pwmLocaleBundle.isAdminOnly(), pwmRequest.getLocale(), pwmRequest.getConfig())%>
+                </td>
+                <td>
+                    <%=numberFormat.format(pwmLocaleBundle.getKeys().size())%>
+                </td>
+                <td>
+                    <%=numberFormat.format(pwmLocaleBundle.getKeys().size() * allStats.getMissingKeys().values().iterator().next().size())%>
+                </td>
+            </tr>
+            <% } %>
+            <tr>
+                <td>
+                    <b>Total</b>
+                </td>
+                <td>
+                </td>
+                <td>
+                    <b><%=numberFormat.format(allStats.getTotalKeys())%></b>
+                </td>
+                <td>
+                    <b><%=numberFormat.format(allStats.getTotalSlots())%></b>
+                </td>
+            </tr>
+        </table>
+
+
+        <h1><a id="end">Localizations (End User Only)</a></h1>
+        <table>
+            <tr>
+                <td class="title">
+                    Name
+                </td>
+                <td class="title">
+                    Key
+                </td>
+                <td class="title">
+                    Present Strings
+                </td>
+                <td class="title">
+                    Missing Strings
+                </td>
+                <td class="title">
+                    Percent Present
+                </td>
+            </tr>
+            <% for (final Locale loopLocale: pwmRequest.getConfig().getKnownLocales()) { %>
+            <% boolean highLight =  (HIGHLIGHTED_LOCALES.contains(loopLocale)); %>
+            <tr<%=highLight ? " class=\"highlight\"" : ""%>>
+                <td>
+                    <%=loopLocale.getDisplayName()%>
+                </td>
+                <td>
+                    <%=loopLocale.toString()%>
+                </td>
+                <td>
+                    <%=userFacingStats.getPerLocale_presentLocalizations().get(loopLocale)%>
+                </td>
+                <td>
+                    <%=userFacingStats.getPerLocale_missingLocalizations().get(loopLocale)%>
+                </td>
+                <td>
+                    <%=userFacingStats.getPerLocale_percentLocalizations().get(loopLocale)%>
+                </td>
+            </tr>
+            <% } %>
+            <tr>
+                <td>
+                    <b>Total</b>
+                </td>
+                <td>
+                </td>
+                <td>
+                    <b><%=numberFormat.format(userFacingStats.getPresentSlots())%></b>
+                </td>
+                <td>
+                    <b><%=numberFormat.format(userFacingStats.getMissingSlots())%></b>
+                </td>
+                <td>
+                    <b><%=userFacingStats.getTotalPercentage()%></b>
+                </td>
+            </tr>
+        </table>
+
+        <h1><a id="2">Localizations (Admin Facing Only)</a></h1>
+        <table>
+            <tr>
+                <td class="title">
+                    Name
+                </td>
+                <td class="title">
+                    Key
+                </td>
+                <td class="title">
+                    Present Strings
+                </td>
+                <td class="title">
+                    Missing Strings
+                </td>
+                <td class="title">
+                    Percent Present
+                </td>
+            </tr>
+            <% for (final Locale loopLocale: pwmRequest.getConfig().getKnownLocales()) { %>
+            <% boolean highLight =  (HIGHLIGHTED_LOCALES.contains(loopLocale)); %>
+            <tr<%=highLight ? " class=\"highlight\"" : ""%>>
+                <td>
+                    <%=loopLocale.getDisplayName()%>
+                </td>
+                <td>
+                    <%=loopLocale.toString()%>
+                </td>
+                <td>
+                    <%=adminFacingStats.getPerLocale_presentLocalizations().get(loopLocale)%>
+                </td>
+                <td>
+                    <%=adminFacingStats.getPerLocale_missingLocalizations().get(loopLocale)%>
+                </td>
+                <td>
+                    <%=adminFacingStats.getPerLocale_percentLocalizations().get(loopLocale)%>
+                </td>
+            </tr>
+            <% } %>
+            <tr>
+                <td>
+                    <b>Total</b>
+                </td>
+                <td>
+                </td>
+                <td>
+                    <b><%=numberFormat.format(adminFacingStats.getPresentSlots())%></b>
+                </td>
+                <td>
+                    <b><%=numberFormat.format(adminFacingStats.getMissingSlots())%></b>
+                </td>
+                <td>
+                    <b><%=adminFacingStats.getTotalPercentage()%></b>
+                </td>
+            </tr>
+        </table>
+
+
+        <h1><a id="localeInfo">Localizations (All)</a></h1>
+        <table>
+            <tr>
+                <td class="title">
+                    Name
+                </td>
+                <td class="title">
+                    Key
+                </td>
+                <td class="title">
+                    Present Strings
+                </td>
+                <td class="title">
+                    Missing Strings
+                </td>
+                <td class="title">
+                    Percent Present
+                </td>
+            </tr>
+            <% for (final Locale loopLocale: pwmRequest.getConfig().getKnownLocales()) { %>
+            <% boolean highLight =  (HIGHLIGHTED_LOCALES.contains(loopLocale)); %>
+            <tr<%=highLight ? " class=\"highlight\"" : ""%>>
+                <td>
+                    <%=loopLocale.getDisplayName()%>
+                </td>
+                <td>
+                    <%=loopLocale.toString()%>
+                </td>
+                <td>
+                    <%=allStats.getPerLocale_presentLocalizations().get(loopLocale)%>
+                </td>
+                <td>
+                    <%=allStats.getPerLocale_missingLocalizations().get(loopLocale)%>
+                </td>
+                <td>
+                    <%=allStats.getPerLocale_percentLocalizations().get(loopLocale)%>
+                </td>
+            </tr>
+            <% } %>
+            <tr>
+                <td>
+                    <b>Total</b>
+                </td>
+                <td>
+                </td>
+                <td>
+                    <b><%=numberFormat.format(allStats.getPresentSlots())%></b>
+                </td>
+                <td>
+                    <b><%=numberFormat.format(allStats.getMissingSlots())%></b>
+                </td>
+                <td>
+                    <b><%=allStats.getTotalPercentage()%></b>
+                </td>
+            </tr>
+        </table>
+
+        <h1><a id="dsada">Configuration Setting Descriptions</a></h1>
+        <table>
+            <tr>
+                <td class="title">
+                    Locale
+                </td>
+                <td class="title">
+                    Key
+                </td>
+                <td class="title">
+                    Present Strings
+                </td>
+                <td class="title">
+                    Missing Strings
+                </td>
+                <td class="title">
+                    Percent Present
+                </td>
+            </tr>
+            <% for (final Locale loopLocale: pwmRequest.getConfig().getKnownLocales()) { %>
+            <% boolean highLight =  (HIGHLIGHTED_LOCALES.contains(loopLocale)); %>
+            <tr<%=highLight ? " class=\"highlight\"" : ""%>>
+                <td>
+                    <%= loopLocale.getDisplayName() %>
+                </td>
+                <td>
+                    <%= loopLocale.toString() %>
+                </td>
+                <td>
+                    <%= configLocaleStats.getDescription_presentLocalizations().get(loopLocale) %>
+                </td>
+                <td>
+                    <%= configLocaleStats.getDescription_missingLocalizations().get(loopLocale) %>
+                </td>
+                <td>
+                    <%= configLocaleStats.getDescription_percentLocalizations().get(loopLocale) %>
+                </td>
+            </tr>
+            <% } %>
+        </table>
+
+        <h1><a id="dsa">Default Challenge Questions</a></h1>
+        <table>
+            <tr>
+                <td class="title">
+                    Locale
+                </td>
+                <td class="title">
+                    Has Default Random Challenge Questions
+                </td>
+            </tr>
+            <% for (final Locale loopLocale: pwmRequest.getConfig().getKnownLocales()) { %>
+            <% boolean highLight =  (HIGHLIGHTED_LOCALES.contains(loopLocale)); %>
+            <tr<%=highLight ? " class=\"highlight\"" : ""%>>
+                <td>
+                    <%= loopLocale.getDisplayName() %>
+                </td>
+                <td>
+                    <%= LocaleHelper.booleanString(configLocaleStats.getDefaultChallenges().contains(loopLocale),  pwmRequest.getLocale(),pwmRequest.getConfig())%>
+                </td>
+            </tr>
+            <% } %>
+        </table>
+
+        <%--
+    <h1><a id="aa">Missing Keys</a></h1>
+    <table>
+        <tr>
+            <td class="title">
+                Bundle
+            </td>
+            <td class="title">
+                Locale
+            </td>
+            <td class="title">
+                Key
+            </td>
+        </tr>
+        <% for (final PwmLocaleBundle pwmLocaleBundle : allStats.getMissingKeys().keySet()) { %>
+        <% for (final Locale locale : allStats.getMissingKeys().get(pwmLocaleBundle).keySet()) { %>
+        <% for (final String key : allStats.getMissingKeys().get(pwmLocaleBundle).get(locale)) { %>
+        <tr>
+            <td>
+                <%=pwmLocaleBundle.getTheClass().getSimpleName()%>
+            </td>
+            <td>
+                <%=locale%>
+            </td>
+            <td>
+                <%=key%>
+            </td>
+        </tr>
+        <% } %>
+        <% } %>
+        <% } %>
+        </table>
+        --%>
+        <br/><br/><br/><br/>
+    </div>
+</div>
+<pwm:script>
+    <script type="text/javascript">
+        PWM_GLOBAL['startupFunctions'].push(function(){
+            PWM_GLOBAL['idle_suspendTimeout'] = true;
+        });
+    </script>
+</pwm:script>
+<% JspUtility.setFlag(pageContext, PwmRequest.Flag.HIDE_FOOTER_TEXT); %>
+<%@ include file="/WEB-INF/jsp/fragment/footer.jsp" %>
+</body>
+</html>

+ 3 - 2
pwm/servlet/web/public/referencedoc.jsp → pwm/servlet/web/public/reference/referencedoc.jsp

@@ -5,6 +5,7 @@
 <%@ page import="password.pwm.event.AuditEvent" %>
 <%@ page import="password.pwm.http.JspUtility" %>
 <%@ page import="password.pwm.i18n.LocaleHelper" %>
+<%@ page import="password.pwm.i18n.PwmLocaleBundle" %>
 <%@ page import="password.pwm.util.StringUtil" %>
 <%@ page import="password.pwm.util.stats.Statistic" %>
 <%@ page import="java.util.*" %>
@@ -72,7 +73,7 @@
             </ol>
             <li><a href="#displayStrings">Display Strings</a></li>
             <ol>
-                <% for (PwmConstants.PwmLocaleBundle bundle : PwmConstants.PwmLocaleBundle.values()) { %>
+                <% for (PwmLocaleBundle bundle : PwmLocaleBundle.values()) { %>
                 <li><a href="#displayStrings_<%=bundle.getTheClass().getSimpleName()%>"><%=bundle.getTheClass().getSimpleName()%></a></li>
                 <% } %>
             </ol>
@@ -316,7 +317,7 @@
         <% } %>
         <% } %>
         <h1><a id="displayStrings">Display Strings</a></h1>
-        <% for (PwmConstants.PwmLocaleBundle bundle : PwmConstants.PwmLocaleBundle.values()) { %>
+        <% for (PwmLocaleBundle bundle : PwmLocaleBundle.values()) { %>
         <h2>
             <a id="displayStrings_<%=bundle.getTheClass().getSimpleName()%>"><%=bundle.getTheClass().getSimpleName()%></a>
             <% if (bundle.isAdminOnly()) { %> (admin-only) <% } %>

+ 1 - 1
pwm/servlet/web/public/rest.jsp → pwm/servlet/web/public/reference/rest.jsp

@@ -27,7 +27,7 @@
 <html dir="<pwm:LocaleOrientation/>">
 <%@ include file="/WEB-INF/jsp/fragment/header.jsp" %>
 <body class="nihilo">
-<style type="text/css">
+<style nonce="<pwm:value name="cspNonce"/>" type="text/css">
     .exampleTD {
         overflow: auto; 
         display: block; 

+ 0 - 0
pwm/servlet/web/public/timezones.jsp → pwm/servlet/web/public/reference/timezones.jsp


+ 15 - 10
pwm/servlet/web/public/resources/configStyle.css

@@ -430,19 +430,24 @@ table {
 }
 
 .editorIdleStatus {
+    /*
     margin-left: auto;
     margin-right: auto;
+    */
+    color: #c3c3c3;
     text-align: center;
     font-size: 10px;
     font-family: "Courier New", Courier, monospace;
-    /*
-    display: table;
-    margin: 0 auto;
-    top: 0;
-    position: absolute;
-    margin-left: 40%;
-    margin-right: 40%;
-    text-align: center;
-    width:20%;
-    */
+    margin-top: 5px;
+    margin-left: 5px;
+    margin-right: 5px;
+    float: right;
+}
+
+.dialogSection {
+    background-color: #eaeaea;
+    padding:5px;
+    border-radius: 3px;
+    margin-left: 5px;
 }
+

+ 2 - 19
pwm/servlet/web/public/resources/js/admin.js

@@ -28,23 +28,6 @@ PWM_ADMIN.initAdminOtherMenu=function() {
     require(["dijit/form/DropDownButton", "dijit/DropDownMenu", "dijit/Menu","dijit/MenuItem", "dijit/PopupMenuItem", "dojo/dom", "dijit/MenuSeparator"],
         function(DropDownButton, DropDownMenu, Menu, MenuItem, PopupMenuItem, dom, MenuSeparator){
             var pMenu = new DropDownMenu({ style: "display: none;"});
-            
-            /*
-            pMenu.addChild(new MenuItem({
-                label: 'Configuration Manager',
-                onClick: function() {
-                    PWM_MAIN.goto('/private/config/ConfigManager');
-                }
-            }));
-            pMenu.addChild(new MenuItem({
-                label: 'Configuration Editor',
-                onClick: function() {
-                    PWM_MAIN.goto('/private/config/ConfigEditor');
-                }
-            }));
-            pMenu.addChild(new MenuSeparator());
-            */
-
             pMenu.addChild(new MenuItem({
                 label: 'Event Log',
                 onClick: function() {
@@ -68,13 +51,13 @@ PWM_ADMIN.initAdminOtherMenu=function() {
             pMenu.addChild(new MenuItem({
                 label: 'Software License Reference',
                 onClick: function() {
-                    PWM_MAIN.newWindowOpen(PWM_GLOBAL['url-context'] + '/public/license.jsp','license');
+                    PWM_MAIN.newWindowOpen(PWM_GLOBAL['url-context'] + '/public/reference/license.jsp','license');
                 }
             }));
             pMenu.addChild(new MenuItem({
                 label: 'Reference',
                 onClick: function() {
-                    PWM_MAIN.newWindowOpen(PWM_GLOBAL['url-context'] + '/public/referencedoc.jsp','referencedoc');
+                    PWM_MAIN.newWindowOpen(PWM_GLOBAL['url-context'] + '/public/reference/referencedoc.jsp','referencedoc');
                 }
             }));
             if (PWM_GLOBAL['setting-displayEula'] == true) {

+ 7 - 0
pwm/servlet/web/public/resources/js/changepassword.js

@@ -192,6 +192,12 @@ PWM_CHANGEPW.copyToPasswordFields = function(text) { // used to copy auto-genera
 
 
 PWM_CHANGEPW.showPasswordGuide=function() {
+    PWM_MAIN.showDialog({
+        showClose:true,
+        title: PWM_MAIN.showString('Title_PasswordGuide'),
+        text: '<div id="passwordGuideTextContent">' + PWM_GLOBAL['passwordGuideText'] + '</div>'
+    });
+    /*
     PWM_MAIN.clearDijitWidget('dialogPopup');
     require(["dojo","dijit/Dialog"],function(dojo, Dialog){
         var theDialog = new Dialog({
@@ -208,6 +214,7 @@ PWM_CHANGEPW.showPasswordGuide=function() {
             dojo.destroy(PWM_MAIN.getObject("passwordGuideTextContent"));
         });
     });
+    */
 };
 
 PWM_CHANGEPW.handleChangePasswordSubmit=function() {

+ 161 - 143
pwm/servlet/web/public/resources/js/configeditor-settings.js

@@ -563,6 +563,15 @@ MultiLocaleTableHandler.writeMultiLocaleSetting = function(settingKey, locale, i
 // -------------------------- form table handler ------------------------------------
 
 var FormTableHandler = {};
+FormTableHandler.newRowValue = {
+    name:'',
+    minimumLength:0,
+    maximumLength:255,
+    labels:{'':''},
+    regexErrors:{'':''},
+    selectOptions:{},
+    description:{'':''}
+};
 
 FormTableHandler.init = function(keyName) {
     console.log('FormTableHandler init for ' + keyName);
@@ -683,9 +692,9 @@ FormTableHandler.drawRow = function(parentDiv, settingKey, iteration, value) {
     });
 };
 
-FormTableHandler.writeFormSetting = function(settingKey) {
+FormTableHandler.writeFormSetting = function(settingKey, finishFunction) {
     var cachedSetting = PWM_VAR['clientSettingCache'][settingKey];
-    PWM_CFGEDIT.writeSetting(settingKey, cachedSetting);
+    PWM_CFGEDIT.writeSetting(settingKey, cachedSetting, finishFunction);
 };
 
 FormTableHandler.removeRow = function(keyName, iteration) {
@@ -694,8 +703,9 @@ FormTableHandler.removeRow = function(keyName, iteration) {
         okAction:function(){
             var currentValues = PWM_VAR['clientSettingCache'][keyName];
             currentValues.splice(iteration,1);
-            FormTableHandler.writeFormSetting(keyName);
-            FormTableHandler.redraw(keyName);
+            FormTableHandler.writeFormSetting(keyName,function(){
+                FormTableHandler.init(keyName);
+            });
         }
     });
 };
@@ -717,15 +727,6 @@ FormTableHandler.arrayMoveUtil = function(arr, fromIndex, toIndex) {
     arr.splice(toIndex, 0, element);
 };
 
-FormTableHandler.newRowValue = {
-    name:'',
-    minimumLength:0,
-    maximumLength:255,
-    labels:{'':''},
-    regexErrors:{'':''},
-    selectOptions:{},
-    description:{'':''}
-};
 
 FormTableHandler.addRow = function(keyName) {
     var body='Name <input class="configStringInput" id="newFormFieldName" style="width:300px"/>';
@@ -738,11 +739,12 @@ FormTableHandler.addRow = function(keyName) {
             }
         });
     },okAction:function(){
-        var newRowValue = FormTableHandler.newRowValue;
-        newRowValue['name'] = PWM_VAR['newFormFieldName'];
-        PWM_VAR['clientSettingCache'][keyName].push(newRowValue);
-        FormTableHandler.writeFormSetting(keyName);
-        FormTableHandler.redraw(keyName)
+        var currentSize = PWM_MAIN.itemCount(PWM_VAR['clientSettingCache'][keyName]);
+        PWM_VAR['clientSettingCache'][keyName][currentSize + 1] = FormTableHandler.newRowValue
+        PWM_VAR['clientSettingCache'][keyName][currentSize + 1].name = PWM_VAR['newFormFieldName'];
+        FormTableHandler.writeFormSetting(keyName,function(){
+            FormTableHandler.init(keyName);
+        });
     }});
 };
 
@@ -1149,7 +1151,9 @@ ChangePasswordHandler.popup = function(settingKey,settingName,writeFunction) {
     if (writeFunction) {
         PWM_VAR['clientSettingCache'][settingKey]['settings']['writeFunction'] = writeFunction;
     } else {
-        PWM_VAR['clientSettingCache'][settingKey]['settings']['writeFunction'] = 'ChangePasswordHandler.doChange(\'' + settingKey + '\')';
+        PWM_VAR['clientSettingCache'][settingKey]['settings']['writeFunction'] = function(passwordValue){
+            ChangePasswordHandler.doChange(settingKey,passwordValue);
+        }
     }
     PWM_VAR['clientSettingCache'][settingKey]['settings']['showFields'] = false;
     ChangePasswordHandler.clear(settingKey);
@@ -1157,24 +1161,22 @@ ChangePasswordHandler.popup = function(settingKey,settingName,writeFunction) {
 };
 
 ChangePasswordHandler.validatePasswordPopupFields = function() {
-    require(["dojo","dijit/registry"],function(dojo,registry){
-        var password1 = registry.byId('password1').get('value');
-        var password2 = registry.byId('password2').get('value');
+        var password1 = PWM_MAIN.getObject('password1').value;
+        var password2 = PWM_MAIN.getObject('password2').value;
 
         var matchStatus = "";
 
-        PWM_MAIN.getObject('password_button').disabled = true;
+        PWM_MAIN.getObject('button-storePassword').disabled = true;
         if (password2.length > 0) {
             if (password1 == password2) {
                 matchStatus = "MATCH";
-                PWM_MAIN.getObject('password_button').disabled = false;
+                PWM_MAIN.getObject('button-storePassword').disabled = false;
             } else {
                 matchStatus = "NO_MATCH";
             }
         }
 
         ChangePasswordHandler.markConfirmationCheck(matchStatus);
-    });
 };
 
 ChangePasswordHandler.markConfirmationCheck = function(matchStatus) {
@@ -1196,13 +1198,15 @@ ChangePasswordHandler.markConfirmationCheck = function(matchStatus) {
     }
 };
 
-ChangePasswordHandler.doChange = function(settingKey) {
-    var password1 = PWM_VAR['clientSettingCache'][settingKey]['settings']['p1'];
-    PWM_MAIN.clearDijitWidget('dialogPopup');
-    PWM_CFGEDIT.writeSetting(settingKey,password1,function(){
-        ChangePasswordHandler.clear(settingKey);
-        ChangePasswordHandler.init(settingKey);
-    });
+ChangePasswordHandler.doChange = function(settingKey, passwordValue) {
+    PWM_MAIN.showWaitDialog({loadFunction:function(){
+        PWM_CFGEDIT.writeSetting(settingKey,passwordValue,function(){
+            ChangePasswordHandler.clear(settingKey);
+            ChangePasswordHandler.init(settingKey);
+            PWM_MAIN.closeWaitDialog();
+        });
+
+    }})
 };
 
 ChangePasswordHandler.clear = function(settingKey) {
@@ -1211,123 +1215,114 @@ ChangePasswordHandler.clear = function(settingKey) {
 };
 
 ChangePasswordHandler.generateRandom = function(settingKey) {
-    ChangePasswordHandler.clear(settingKey);
+    var length = PWM_VAR['passwordDialog-randomLength'];
+    var special = PWM_VAR['passwordDialog-special'];
+
     if (!PWM_VAR['clientSettingCache'][settingKey]['settings']['showFields']) {
         PWM_VAR['clientSettingCache'][settingKey]['settings']['showFields'] = true;
-        ChangePasswordHandler.changePasswordPopup(settingKey);
     }
-    require(["dojo","dijit/registry"],function(dojo,registry){
-        var charMap = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
-        if (registry.byId('special').checked) {
-            charMap += '~`!@#$%^&*()_-+=;:,.[]{}';
-        }
-        var length = registry.byId('randomLength').value;
-        var postData = { };
-        postData.maxLength = length;
-        postData.minLength = length;
-        postData.chars = charMap;
-        postData.noUser = true;
-        PWM_MAIN.getObject('generateButton').disabled = true;
-
-        dojo.xhrPost({
-            url:PWM_GLOBAL['url-restservice'] + "/randompassword",
-            preventCache: true,
-            headers: {"Accept":"application/json","X-RestClientKey":PWM_GLOBAL['restClientKey']},
-            postData: postData,
-            dataType: "json",
-            handleAs: "json",
-            load: function(data) {
-                registry.byId('password1').set('value',data['data']['password']);
-                registry.byId('password2').set('value','');
-                PWM_MAIN.getObject('generateButton').disabled = false;
-            },
-            error: function(error) {
-                PWM_MAIN.getObject('generateButton').disabled = false;
-                alert('error reading random password: ' + error);
-            }
-        });
-    });
+
+    var charMap = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+    if (special) {
+        charMap += '~`!@#$%^&*()_-+=;:,.[]{}';
+    }
+    var postData = { };
+    postData.maxLength = length;
+    postData.minLength = length;
+    postData.chars = charMap;
+    postData.noUser = true;
+    PWM_MAIN.getObject('button-storePassword').disabled = true;
+
+    var url = PWM_GLOBAL['url-restservice'] + "/randompassword";
+    var loadFunction = function(data) {
+        ChangePasswordHandler.changePasswordPopup(settingKey);
+        PWM_MAIN.getObject('password1').value = data['data']['password'];
+        PWM_MAIN.getObject('password2').value = '';
+        PWM_MAIN.getObject('button-storePassword').disabled = false;
+    };
+
+    PWM_MAIN.showWaitDialog({loadFunction:function(){
+        PWM_MAIN.ajaxRequest(url,loadFunction,{content:postData});
+    }});
 };
 
 ChangePasswordHandler.changePasswordPopup = function(settingKey) {
     var writeFunction = PWM_VAR['clientSettingCache'][settingKey]['settings']['writeFunction'];
-    require(["dojo/parser","dijit/registry","dijit/Dialog","dijit/form/Textarea","dijit/form/TextBox","dijit/form/NumberSpinner","dijit/form/CheckBox"],
-        function(dojoParser,registry,Dialog,Textarea,TextBox)
-        {
-            /*
-             var bodyText = '<div id="changePasswordDialogDiv">'
-             + '<span id="message" class="message message-info">' + PWM_VAR['clientSettingCache'][settingKey]['settings']['name'] + '</span><br/>'
-             */
-            var bodyText = '<table style="border: 0">'
-                + '<tr style="border: 0"><td style="border: 0">' + PWM_MAIN.showString('Field_NewPassword') + '</td></tr>'
-                + '<tr style="border: 0"><td style="border: 0">'
-                + '<input name="password1" id="password1" class="inputfield" style="width: 500px; max-height: 200px; overflow: auto" autocomplete="off">' + '</input>'
-                + '</td></tr><tr style="border:0"><td style="border:0">&nbsp;</td></tr>'
-                + '<tr style="border: 0"><td style="border: 0">' + PWM_MAIN.showString('Field_ConfirmPassword') + '</span></td></tr>'
-                + '<tr style="border: 0">'
-                + '<td style="border: 0" xmlns="http://www.w3.org/1999/html"><input name="password2" id="password2" class="inputfield" style="width: 500px; max-height: 200px; overflow: auto;" autocomplete="off"/></input></td>'
-
-                + '<td style="border: 0"><div style="margin:0;">'
-                + '<img style="visibility:hidden;" id="confirmCheckMark" alt="checkMark" height="15" width="15" src="' + PWM_GLOBAL['url-resources'] + '/greenCheck.png">'
-                + '<img style="visibility:hidden;" id="confirmCrossMark" alt="crossMark" height="15" width="15" src="' + PWM_GLOBAL['url-resources'] + '/redX.png">'
-                + '</div></td>'
-
-                + '</tr></table>'
-                + '<button name="change" class="btn" id="password_button" onclick="' + writeFunction + '" disabled="true"/>'
-                + '<span class="fa fa-forward btn-icon"></span>Store Password</button>&nbsp;&nbsp;'
-                + '<button id="generateButton" name="generateButton" class="btn" onclick="ChangePasswordHandler.generateRandom(\'' + settingKey + '\')"><span class="fa fa-random btn-icon"></span>Random</button>'
-                + '&nbsp;&nbsp;<input style="width:60px" data-dojo-props="constraints: { min:1, max:102400 }" data-dojo-type="dijit/form/NumberSpinner" id="randomLength" value="32"/>Length'
-                + '&nbsp;&nbsp;<input type="checkbox" id="special" data-dojo-type="dijit/form/CheckBox" value="10"/>Special'
-                + '&nbsp;&nbsp;<input type="checkbox" id="show" data-dojo-type="dijit/form/CheckBox" data-dojo-props="checked:' + PWM_VAR['clientSettingCache'][settingKey]['settings']['showFields'] + '" value="10"/>Show'
-                + '</div>';
+    var showFields = PWM_VAR['clientSettingCache'][settingKey]['settings']['showFields'];
+    var p1 = PWM_VAR['clientSettingCache'][settingKey]['settings']['p1'];
+    var p2 = PWM_VAR['clientSettingCache'][settingKey]['settings']['p2'];
+    var length = 'passwordDialog-randomLength' in PWM_VAR ? PWM_VAR['passwordDialog-randomLength'] : 25;
+    var special = 'passwordDialog-special' in PWM_VAR ? PWM_VAR['passwordDialog-special'] : false;
+
+    var bodyText = '<table class="noborder">'
+        + '<tr><td><span class="formFieldLabel">' + PWM_MAIN.showString('Field_NewPassword') + '</span></td></tr>'
+        + '<tr><td>';
+
+    if (showFields) {
+        bodyText += '<textarea name="password1" id="password1" class="configStringInput" style="width: 400px; max-width: 400px; max-height:100px; overflow-y: auto" autocomplete="off">' + p1 + '</textarea>';
+    } else {
+        bodyText += '<input name="password1" id="password1" class="configStringInput" type="password" style="width: 400px;" autocomplete="off" value="' + p1 + '"></input>';
+    }
 
-            PWM_MAIN.showDialog({
-                title: 'Store Password - ' + PWM_VAR['clientSettingCache'][settingKey]['settings']['name'],
-                text: bodyText,
-                showOk: false,
-                showClose: true
-            });
+    bodyText += '</td></tr>'
+    + '<tr><td><span class="formFieldLabel">' + PWM_MAIN.showString('Field_ConfirmPassword') + '</span></td></tr>'
+    + '<tr><td>';
 
-            registry.byId('show').set('onChange',function(){
-                PWM_VAR['clientSettingCache'][settingKey]['settings']['showFields'] = this.checked;
+    if (showFields) {
+        bodyText += '<textarea name="password2" id="password2" class="configStringInput" style="width: 400px; max-width: 400px; max-height:100px; overflow-y: auto" autocomplete="off">' + p2 + '</textarea>';
+    } else {
+        bodyText += '<input name="password2" type="password" id="password2" class="configStringInput" style="width: 400px;" autocomplete="off" value="' + p2 + '"></input>';
+    }
+
+    bodyText += '</td>'
+    + '<td><div style="margin:0;">'
+    + '<img style="visibility:hidden;" id="confirmCheckMark" alt="checkMark" height="15" width="15" src="' + PWM_GLOBAL['url-resources'] + '/greenCheck.png">'
+    + '<img style="visibility:hidden;" id="confirmCrossMark" alt="crossMark" height="15" width="15" src="' + PWM_GLOBAL['url-resources'] + '/redX.png">'
+    + '</div></td>'
+    + '</tr></table>'
+    + '<br/><br/><div class="dialogSection" style="width: 400px"><span class="formFieldLabel">Generate Random Password </span><br/>'
+    + '<label class="checkboxWrapper"><input id="input-special" type="checkbox"' + (special ? ' checked' : '') + '>Specials</input></label>'
+    + '&nbsp;&nbsp;&nbsp;&nbsp;<input id="input-randomLength" type="number" min="10" max="1000" value="' + length + '" style="width:45px">Length'
+    + '&nbsp;&nbsp;&nbsp;&nbsp;<button id="button-generateRandom" name="button-generateRandom"><span class="fa fa-random btn-icon"></span>Generate Random</button>'
+    + '</div><br/><br/>'
+    + '<button name="button-storePassword" class="btn" id="button-storePassword" disabled="true"/>'
+    + '<span class="fa fa-forward btn-icon"></span>Store Password</button>&nbsp;&nbsp;'
+    + '<label class="checkboxWrapper"><input id="show" type="checkbox"' + (showFields ? ' checked' : '') + '>Show Passwords</input></label>'
+    + '</div><br/><br/>';
+
+    PWM_MAIN.showDialog({
+        title: 'Store Password - ' + PWM_VAR['clientSettingCache'][settingKey]['settings']['name'],
+        text: bodyText,
+        showOk: false,
+        showClose: true,
+        loadFunction:function(){
+            PWM_MAIN.addEventHandler('button-storePassword','click',function() {
+                var passwordValue = PWM_MAIN.getObject('password1').value;
+                PWM_MAIN.closeWaitDialog();
+                writeFunction(passwordValue);
+            });
+            PWM_MAIN.addEventHandler('button-generateRandom','click',function() {
+                PWM_VAR['passwordDialog-randomLength'] = PWM_MAIN.getObject('input-randomLength').value;
+                PWM_VAR['passwordDialog-special'] = PWM_MAIN.getObject('input-special').checked;
+                ChangePasswordHandler.generateRandom(settingKey);
+            });
+            PWM_MAIN.addEventHandler('password1','input',function(){
+                PWM_VAR['clientSettingCache'][settingKey]['settings']['p1'] = PWM_MAIN.getObject('password1').value;
+                ChangePasswordHandler.validatePasswordPopupFields();
+                PWM_MAIN.getObject('password2').value = '';
+            });
+            PWM_MAIN.addEventHandler('password2','input',function(){
+                PWM_VAR['clientSettingCache'][settingKey]['settings']['p2'] = PWM_MAIN.getObject('password2').value;
+                ChangePasswordHandler.validatePasswordPopupFields();
+            });
+            PWM_MAIN.addEventHandler('show','change',function(){
+                PWM_VAR['clientSettingCache'][settingKey]['settings']['showFields'] = PWM_MAIN.getObject('show').checked;
                 ChangePasswordHandler.changePasswordPopup(settingKey);
             });
-
-            dojoParser.parse(PWM_MAIN.getObject('changePasswordDialogDiv'));
-
-            var p1 = PWM_VAR['clientSettingCache'][settingKey]['settings']['p1'];
-            var p2 = PWM_VAR['clientSettingCache'][settingKey]['settings']['p2'];
-            var p1Options = {
-                id: 'password1',
-                style: 'width: 100%',
-                type: 'password',
-                onKeyUp: function(){
-                    PWM_VAR['clientSettingCache'][settingKey]['settings']['p1'] = this.get('value');
-                    ChangePasswordHandler.validatePasswordPopupFields();
-                    registry.byId('password2').set('value','')
-                },
-                value: p1
-            };
-            var p2Options = {
-                id: 'password2',
-                style: 'width: 100%',
-                type: 'password',
-                onKeyUp: function(){
-                    PWM_VAR['clientSettingCache'][settingKey]['settings']['p2'] = this.get('value');
-                    ChangePasswordHandler.validatePasswordPopupFields();
-                },
-                value: p2
-            };
-            if (PWM_VAR['clientSettingCache'][settingKey]['settings']['showFields']) {
-                new Textarea(p1Options,'password1');
-                new Textarea(p2Options,'password2');
-            } else {
-                new TextBox(p1Options,'password1');
-                new TextBox(p2Options,'password2');
-            }
             PWM_MAIN.getObject('password1').focus();
             ChangePasswordHandler.validatePasswordPopupFields();
-        });
+        }
+    });
 };
 
 
@@ -1340,6 +1335,7 @@ ActionHandler.defaultValue = {
     description:"",
     type:"webservice",
     method:"get",
+    ldapMethod:"replace",
     url:"",
     body:"",
     headers:{},
@@ -1352,6 +1348,11 @@ ActionHandler.httpMethodOptions = [
     { label: "Post", value: "post" },
     { label: "Put", value: "put" }
 ];
+ActionHandler.ldapMethodOptions = [
+    { label: "Replace", value: "replace" },
+    { label: "Add", value: "add" },
+    { label: "Remove", value: "remove" }
+];
 
 ActionHandler.init = function(keyName) {
     console.log('ActionHandler init for ' + keyName);
@@ -1465,9 +1466,9 @@ ActionHandler.drawRow = function(parentDiv, settingKey, iteration, value) {
     });
 };
 
-ActionHandler.writeFormSetting = function(settingKey) {
+ActionHandler.writeFormSetting = function(settingKey, finishFunction) {
     var cachedSetting = PWM_VAR['clientSettingCache'][settingKey];
-    PWM_CFGEDIT.writeSetting(settingKey, cachedSetting);
+    PWM_CFGEDIT.writeSetting(settingKey, cachedSetting, finishFunction);
 };
 
 ActionHandler.removeRow = function(keyName, iteration) {
@@ -1476,8 +1477,9 @@ ActionHandler.removeRow = function(keyName, iteration) {
         okAction:function(){
             delete PWM_VAR['clientSettingCache'][keyName][iteration];
             console.log("removed iteration " + iteration + " from " + keyName + ", cached keyValue=" + PWM_VAR['clientSettingCache'][keyName]);
-            ActionHandler.writeFormSetting(keyName);
-            ActionHandler.redraw(keyName);
+            ActionHandler.writeFormSetting(keyName,function(){
+                ActionHandler.init(keyName);
+            });
         }
     })
 };
@@ -1496,8 +1498,10 @@ ActionHandler.addRow = function(keyName) {
         var currentSize = PWM_MAIN.itemCount(PWM_VAR['clientSettingCache'][keyName]);
         PWM_VAR['clientSettingCache'][keyName][currentSize + 1] = ActionHandler.defaultValue;
         PWM_VAR['clientSettingCache'][keyName][currentSize + 1].name = PWM_VAR['newActionName'];
-        ActionHandler.writeFormSetting(keyName);
-        ActionHandler.redraw(keyName)
+        ActionHandler.writeFormSetting(keyName,function(){
+            ActionHandler.init(keyName);
+        });
+
     }});
 };
 
@@ -1514,7 +1518,7 @@ ActionHandler.showOptionsDialog = function(keyName, iteration) {
             bodyText += '<td class="key">HTTP Method</td><td style="border:0;"><select id="select-' + inputID + '-method' + '">';
 
             for (var optionItem in ActionHandler.httpMethodOptions) {
-                var label = ActionHandler.httpMethodOptions[optionItem]['label']
+                var label = ActionHandler.httpMethodOptions[optionItem]['label'];
                 var optionValue = ActionHandler.httpMethodOptions[optionItem]['value'];
                 var selected = optionValue == PWM_VAR['clientSettingCache'][keyName][iteration]['method'];
                 bodyText += '<option value="' + optionValue + '"' + (selected ? ' selected' : '') + '>' + label + '</option>';
@@ -1534,6 +1538,16 @@ ActionHandler.showOptionsDialog = function(keyName, iteration) {
             bodyText += '</tr><tr>';
             bodyText += '<td class="key">Attribute Value</td><td><input style="width:300px" class="configStringInput" type="text" id="input-' + inputID + '-attributeValue' + '" value="' + value['attributeValue'] + '"/></td>';
             bodyText += '</tr>';
+            bodyText += '<tr>';
+            bodyText += '<td class="key">Operation Type</td><td style="border:0;"><select id="select-' + inputID + '-ldapMethod' + '">';
+
+            for (var optionItem in ActionHandler.ldapMethodOptions) {
+                var label = ActionHandler.ldapMethodOptions[optionItem]['label'];
+                var optionValue = ActionHandler.ldapMethodOptions[optionItem]['value'];
+                var selected = optionValue == PWM_VAR['clientSettingCache'][keyName][iteration]['ldapMethod'];
+                bodyText += '<option value="' + optionValue + '"' + (selected ? ' selected' : '') + '>' + label + '</option>';
+            }
+            bodyText += '</td></tr>';
         }
         bodyText += '</table>';
 
@@ -1567,6 +1581,10 @@ ActionHandler.showOptionsDialog = function(keyName, iteration) {
                         PWM_VAR['clientSettingCache'][keyName][iteration]['attributeValue'] = PWM_MAIN.getObject('input-' + inputID + '-attributeValue').value;
                         ActionHandler.writeFormSetting(keyName);
                     });
+                    PWM_MAIN.addEventHandler('select-' + inputID + '-ldapMethod','input',function(){
+                        PWM_VAR['clientSettingCache'][keyName][iteration]['ldapMethod'] = PWM_MAIN.getObject('select-' + inputID + '-ldapMethod').value;
+                        ActionHandler.writeFormSetting(keyName);
+                    });
                 }
             }
         });

+ 5 - 3
pwm/servlet/web/public/resources/js/configeditor.js

@@ -327,7 +327,9 @@ PWM_CFGEDIT.setConfigurationPassword = function(password) {
         return;
     }
 
-    var writeFunction = 'PWM_CFGEDIT.setConfigurationPassword(PWM_MAIN.getObject(\'password1\').value)';
+    var writeFunction = function(passwordValue) {
+        PWM_CFGEDIT.setConfigurationPassword(passwordValue);
+    };
     ChangePasswordHandler.popup('configPw','Configuration Password',writeFunction);
 };
 
@@ -401,7 +403,7 @@ PWM_CFGEDIT.initConfigEditor = function(nextFunction) {
     PWM_MAIN.addEventHandler('saveButton_icon','click',function(){PWM_CFGEDIT.saveConfiguration()});
     PWM_MAIN.addEventHandler('setPassword_icon','click',function(){PWM_CFGEDIT.setConfigurationPassword()});
     PWM_MAIN.addEventHandler('referenceDoc_icon','click',function(){
-        PWM_MAIN.newWindowOpen(PWM_GLOBAL['url-context'] + '/public/referencedoc.jsp#settings','referencedoc');
+        PWM_MAIN.newWindowOpen(PWM_GLOBAL['url-context'] + '/public/reference/referencedoc.jsp#settings','referencedoc');
     });
     PWM_MAIN.addEventHandler('macroDoc_icon','click',function(){ PWM_CFGEDIT.showMacroHelp(); });
     PWM_MAIN.addEventHandler('settingFilter_icon','click',function(){ PWM_CFGEDIT.showSettingFilter(); });
@@ -713,7 +715,7 @@ PWM_CFGEDIT.showTimezoneList = function() {
             id: idName,
             title: 'Timezones',
             style: "width: 750px",
-            href: PWM_GLOBAL['url-context'] + "/public/timezones.jsp"
+            href: PWM_GLOBAL['url-context'] + "/public/reference/timezones.jsp"
         });
         theDialog.show();
     });

+ 81 - 25
pwm/servlet/web/public/resources/js/main.js

@@ -269,7 +269,7 @@ PWM_MAIN.applyFormAttributes = function() {
         );
 
         array.forEach(
-            query("a"),
+            query("a:not([target])"),
             function(linkElement){
                 var hrefValue = linkElement.getAttribute('href');
                 if (hrefValue && hrefValue.charAt(0) != '#') {
@@ -728,21 +728,30 @@ PWM_MAIN.showWaitDialog = function(options) {
             });
         };
         options['title'] = options['title'] || PWM_MAIN.showString('Display_PleaseWait');
-        options['text'] = options['text'] || '<div id="progressBar" style="margin: 8px; width: 100%"/>';
+        var supportsProgress = (document.createElement('progress').max !== undefined);
+        if (supportsProgress) {
+            options['text'] = options['text'] || '<progress id="wait">';
+        } else {
+            options['text'] = options['text'] || '<div id="progressBar" style="margin: 8px; width: 100%"/>';
+        }
+
+
         options['dialogClass'] = 'narrow';
         options['showOk'] = false;
 
-        /*
-         var overlayDiv = document.createElement('div');
-         overlayDiv.setAttribute("style","background-color: #000; opacity: .5; filter: alpha(opacity=50); position: absolute; top: 0; left: 0; width: 100%; height: 100%;z-index: 10;");
-         document.body.appendChild(overlayDiv);
-         */
-
         PWM_MAIN.showDialog(options);
     });
 };
 
+PWM_MAIN.html5DialogSupport = function() {
+    var testdialog=document.createElement("dialog");
+    testdialog.setAttribute("open", "");
+    return (testdialog.open==true);
+};
+
 PWM_MAIN.showDialog = function(options) {
+    var html5Dialog = PWM_MAIN.html5DialogSupport();
+
     options = options === undefined ? {} : options;
     var title = options['title'] || 'DialogTitle';
     var text = 'text' in options ? options['text'] : 'DialogBody';
@@ -800,29 +809,68 @@ PWM_MAIN.showDialog = function(options) {
 
     bodyText = '<div class="' + dialogClassText + '">' + bodyText + '</div>';
 
-    require(["dojo","dijit/Dialog"],function(dojo,Dialog){
-        PWM_MAIN.clearDijitWidget(idName);
-        var theDialog = new Dialog({
-            id: idName,
-            closable: showClose,
-            draggable: allowMove,
-            title: title,
-            content: bodyText
-        });
-        if (!showClose) {
-            dojo.style(theDialog.closeButtonNode, "display", "none");
+    if (html5Dialog) {
+        PWM_MAIN.closeWaitDialog();
+        var dialogElement = document.createElement("dialog");
+        dialogElement.setAttribute("id", 'html5Dialog');
+        //dialogElement.setAttribute("draggable","true");
+        var html5DialogHtml = '<div class="titleBar">' + title;
+        if (showClose) {
+            html5DialogHtml += '<div id="icon-closeDialog" class="closeIcon fa fa-times"></div>'
         }
-        dojo.connect(theDialog,"onShow",null,function(){
+        html5DialogHtml += '</div><div class="body">' + bodyText + '</div>';
+        dialogElement.innerHTML = html5DialogHtml;
+        document.body.appendChild(dialogElement);
+        dialogElement.showModal();
+
+        setTimeout(function () {
             if (showOk) {
-                PWM_MAIN.addEventHandler('dialog_ok_button','click',function(){okAction()});
+                PWM_MAIN.addEventHandler('dialog_ok_button', 'click', function () {
+                    okAction()
+                });
+            }
+            if (showClose) {
+                PWM_MAIN.addEventHandler('icon-closeDialog', 'click', function () {
+                    PWM_MAIN.closeWaitDialog();
+                });
             }
+
             if (showCancel) {
-                PWM_MAIN.addEventHandler('dialog_cancel_button','click',function(){cancelAction()});
+                PWM_MAIN.addEventHandler('dialog_cancel_button', 'click', function () {
+                    cancelAction()
+                });
+            }
+            setTimeout(loadFunction, 100);
+        }, 100);
+    } else {
+        require(["dojo", "dijit/Dialog"], function (dojo, Dialog) {
+            PWM_MAIN.clearDijitWidget(idName);
+            var theDialog = new Dialog({
+                id: idName,
+                closable: showClose,
+                draggable: allowMove,
+                title: title,
+                content: bodyText
+            });
+            if (!showClose) {
+                dojo.style(theDialog.closeButtonNode, "display", "none");
             }
-            setTimeout(loadFunction,100);
+            dojo.connect(theDialog, "onShow", null, function () {
+                if (showOk) {
+                    PWM_MAIN.addEventHandler('dialog_ok_button', 'click', function () {
+                        okAction()
+                    });
+                }
+                if (showCancel) {
+                    PWM_MAIN.addEventHandler('dialog_cancel_button', 'click', function () {
+                        cancelAction()
+                    });
+                }
+                setTimeout(loadFunction, 100);
+            });
+            theDialog.show();
         });
-        theDialog.show();
-    });
+    }
 };
 
 PWM_MAIN.showEula = function(requireAgreement, agreeFunction) {
@@ -861,6 +909,14 @@ PWM_MAIN.showConfirmDialog = function(options) {
 };
 
 PWM_MAIN.closeWaitDialog = function(idName) {
+    var html5Mode = PWM_MAIN.html5DialogSupport();
+    if (html5Mode) {
+        if (PWM_MAIN.getObject('html5Dialog')) {
+            PWM_MAIN.getObject('html5Dialog').parentNode.removeChild(PWM_MAIN.getObject('html5Dialog'));
+        }
+        return;
+    }
+
     idName = idName == undefined ? 'dialogPopup' : idName;
     PWM_MAIN.clearDijitWidget(idName);
 };

+ 46 - 1
pwm/servlet/web/public/resources/style.css

@@ -243,7 +243,7 @@ input[type=password]::-ms-reveal{display: none;}
 
 .btn {
     border-style:none;
-    padding: 3px 11px;
+    padding: 4px 12px;
     margin: 9px 7px;
     text-decoration: none;
     color: white;
@@ -763,5 +763,50 @@ input[type=search] {
 
 .formFieldWrapper {
     padding-bottom: 10px;
+}
+
+
+dialog::backdrop { background: rgba(0,0,0,0.6); }
+
+dialog {
+    /*
+    position: absolute;
+    top:0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+
+    margin: auto;
+
+
+    padding-top: 0;
+    */
+    border: 2px solid #DDDDDD;
+    border-radius: 3px;
+    padding:0;
+}
+
+dialog .titleBar {
+    text-align: center;
+    font-weight: bold;
+    padding-top: 3px;
+    padding-bottom: 3px;
+    background-color: #eaeaea;
+    margin-bottom: 5px;
 
+}
+
+dialog .body {
+    padding:5px;
+}
+
+dialog .closeIcon {
+    float: right;
+    cursor: pointer;
+    margin-right: 3px;
+}
+
+progress:not([value]) {
+    width: 100%;
+    height: 20px;
 }

+ 5 - 5
pwm/servlet/web/public/resources/themes/pwm/style.css

@@ -3,7 +3,7 @@
  * http://code.google.com/p/pwm/
  *
  * Copyright (c) 2006-2009 Novell, Inc.
- * Copyright (c) 2009-2014 The PWM Project
+ * Copyright (c) 2009-2015 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
@@ -33,7 +33,7 @@
 .btn {
     font-family: Trebuchet MS, sans-serif;
     border-radius: 3px;
-    box-shadow: 2px 2px 1px 1px #8c8c8c;
+    /* box-shadow: 2px 2px 1px 1px #8c8c8c; */
     background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #3e374c), color-stop(1, #08070f) );
     background:linear-gradient(to bottom, #3e374c 5%, #08070f 100% );
 }.btn:hover {
@@ -54,7 +54,7 @@
     color: black;
     white-space: normal;
     background: #E8E1F6;
-    box-shadow: 2px 2px 1px 1px #8c8c8c;
+    /* box-shadow: 2px 2px 1px 1px #8c8c8c; */
     background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #E8E1F6), color-stop(1, #B2B1B9) );
     background:linear-gradient(to bottom, #E8E1F6 5%, #B2B1B9 100% );
 }.menubutton:hover {
@@ -63,7 +63,7 @@
 }
 
 .inputfield {
-    box-shadow: 2px 2px 2px 2px #f1f1f1;
+    /* box-shadow: 2px 2px 2px 2px #f1f1f1; */
     padding-left: 3px;
     padding-right: 3px;
     font-size: 10pt;
@@ -71,7 +71,7 @@
 }
 
 .changepasswordfield {
-    box-shadow: 2px 2px 2px 2px #f1f1f1;
+    /* box-shadow: 2px 2px 2px 2px #f1f1f1; */
     font-size: 10pt;
     font-family: monospace;
 }