瀏覽代碼

new user value injection enhancements

Jason Rivard 8 年之前
父節點
當前提交
ef1d6bf11e

+ 1 - 0
src/main/java/password/pwm/AppProperty.java

@@ -290,6 +290,7 @@ public enum     AppProperty {
     WORDLIST_CHAR_LENGTH_MAX                        ("wordlist.maxCharLength"),
     WORDLIST_CHAR_LENGTH_MIN                        ("wordlist.minCharLength"),
     WS_REST_CLIENT_PWRULE_HALTONERROR               ("ws.restClient.pwRule.haltOnError"),
+    WS_REST_SERVER_SIGNING_FORM_TIMEOUT_SECONDS     ("ws.restServer.signing.form.timeoutSeconds"),
     ALLOW_MACRO_IN_REGEX_SETTING                    ("password.policy.allowMacroInRegexSetting"),
 
     ;

+ 1 - 0
src/main/java/password/pwm/bean/SessionLabel.java

@@ -37,6 +37,7 @@ public class SessionLabel implements Serializable {
     public static final SessionLabel CLI_SESSION_LABEL= new SessionLabel(SESSION_LABEL_SESSION_ID ,null,"cli",null,null);
     public static final SessionLabel HEALTH_SESSION_LABEL = new SessionLabel(SESSION_LABEL_SESSION_ID ,null,"health",null,null);
     public static final SessionLabel REPORTING_SESSION_LABEL = new SessionLabel(SESSION_LABEL_SESSION_ID ,null,"reporting",null,null);
+    public static final SessionLabel AUDITING_SESSION_LABEL = new SessionLabel(SESSION_LABEL_SESSION_ID ,null,"auditing",null,null);
 
     private final String sessionID;
     private final UserIdentity userIdentity;

+ 6 - 0
src/main/java/password/pwm/config/FormConfiguration.java

@@ -266,6 +266,12 @@ public class FormConfiguration implements Serializable {
 
     public void checkValue(final Configuration config, final String value, final Locale locale)
             throws PwmDataValidationException, PwmUnrecoverableException {
+
+        // ignore read only fields
+        if (readonly) {
+            return;
+        }
+
         //check if value is missing and required.
         if (required && (value == null || value.length() < 1)) {
             final ErrorInformation error = new ErrorInformation(PwmError.ERROR_FIELD_REQUIRED, null, new String[]{getLabel(locale)});

+ 1 - 1
src/main/java/password/pwm/config/FormUtility.java

@@ -90,7 +90,7 @@ public class FormUtility {
             final String keyName = formItem.getName();
             final String value = inputMap.get(keyName);
 
-            if (formItem.isRequired()) {
+            if (formItem.isRequired() && !formItem.isReadonly()) {
                 if (value == null || value.length() < 0) {
                     final String errorMsg = "missing required value for field '" + formItem.getName() + "'";
                     final ErrorInformation error = new ErrorInformation(PwmError.ERROR_FIELD_REQUIRED, errorMsg, new String[]{formItem.getLabel(locale)});

+ 1 - 0
src/main/java/password/pwm/http/PwmRequestAttribute.java

@@ -38,6 +38,7 @@ public enum PwmRequestAttribute {
     CspNonce,
 
     FormConfiguration,
+    FormInitialValues,
     FormReadOnly,
     FormShowPasswordFields,
     FormData,

+ 17 - 37
src/main/java/password/pwm/http/bean/NewUserBean.java

@@ -22,16 +22,14 @@
 
 package password.pwm.http.bean;
 
-import lombok.AllArgsConstructor;
+import com.google.gson.annotations.SerializedName;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
 import lombok.Setter;
 import password.pwm.bean.TokenVerificationProgress;
 import password.pwm.config.option.SessionBeanMode;
-import password.pwm.error.PwmUnrecoverableException;
-import password.pwm.util.PasswordData;
+import password.pwm.http.servlet.newuser.NewUserForm;
 
-import java.io.Serializable;
 import java.time.Instant;
 import java.util.Arrays;
 import java.util.Collections;
@@ -43,49 +41,31 @@ import java.util.Set;
 @Setter
 @NoArgsConstructor
 public class NewUserBean extends PwmSessionBean {
+    @SerializedName("p")
     private String profileID;
+
+    @SerializedName("f")
     private NewUserForm newUserForm;
 
+    @SerializedName("r")
     private Map<String,String> remoteInputData;
-    private boolean agreementPassed;
-    private boolean formPassed;
-    private Instant createStartTime;
-    private boolean urlSpecifiedProfile;
-    private final TokenVerificationProgress tokenVerificationProgress = new TokenVerificationProgress();
-
-    @Getter
-    @AllArgsConstructor
-    public static class
-    NewUserForm implements Serializable {
-        private final Map<String,String> formData;
-        private final PasswordData newUserPassword;
-        private final PasswordData confirmPassword;
 
-        public boolean isConsistentWith(final NewUserForm otherForm) throws PwmUnrecoverableException {
-            if (otherForm == null) {
-                return false;
-            }
+    @SerializedName("ap")
+    private boolean agreementPassed;
 
-            if (newUserPassword != null && otherForm.newUserPassword == null || newUserPassword == null && otherForm.newUserPassword != null) {
-                return false;
-            }
+    @SerializedName("fp")
+    private boolean formPassed;
 
-            if (newUserPassword == null || !newUserPassword.getStringValue().equals(otherForm.newUserPassword.getStringValue())) {
-                return false;
-            }
+    @SerializedName("t")
+    private Instant createStartTime;
 
-            for (final String formKey : formData.keySet()) {
-                final String value = formData.get(formKey);
-                final String otherValue = otherForm.formData.get(formKey);
-                if (value != null && !value.equals(otherValue)) {
-                    return false;
-                }
-            }
+    @SerializedName("u")
+    private boolean urlSpecifiedProfile;
 
-            return true;
-        }
-    }
+    @SerializedName("v")
+    private final TokenVerificationProgress tokenVerificationProgress = new TokenVerificationProgress();
 
+    @Override
     public Type getType() {
         return Type.PUBLIC;
     }

+ 71 - 0
src/main/java/password/pwm/http/servlet/newuser/NewUserForm.java

@@ -0,0 +1,71 @@
+/*
+ * Password Management Servlets (PWM)
+ * http://www.pwm-project.org
+ *
+ * Copyright (c) 2006-2009 Novell, Inc.
+ * Copyright (c) 2009-2017 The PWM Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package password.pwm.http.servlet.newuser;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import password.pwm.error.PwmUnrecoverableException;
+import password.pwm.util.PasswordData;
+
+import java.io.Serializable;
+import java.util.Map;
+
+@Getter
+@AllArgsConstructor
+public class NewUserForm implements Serializable {
+
+    @SerializedName("f")
+    private final Map<String,String> formData;
+
+    @SerializedName("p")
+    private final PasswordData newUserPassword;
+
+    @SerializedName("c")
+    private final PasswordData confirmPassword;
+
+    public boolean isConsistentWith(final 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 String formKey : formData.keySet()) {
+            final String value = formData.get(formKey);
+            final String otherValue = otherForm.formData.get(formKey);
+            if (value != null && !value.equals(otherValue)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}

+ 66 - 94
src/main/java/password/pwm/http/servlet/newuser/NewUserFormUtils.java

@@ -22,12 +22,11 @@
 
 package password.pwm.http.servlet.newuser;
 
-import password.pwm.AppProperty;
 import password.pwm.config.FormConfiguration;
 import password.pwm.config.FormUtility;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.profile.NewUserProfile;
-import password.pwm.config.profile.PwmPasswordPolicy;
+import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmDataValidationException;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmOperationalException;
@@ -36,11 +35,12 @@ import password.pwm.http.PwmRequest;
 import password.pwm.http.bean.NewUserBean;
 import password.pwm.svc.token.TokenPayload;
 import password.pwm.util.PasswordData;
-import password.pwm.util.RandomPasswordGenerator;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.SecureService;
 
 import java.io.IOException;
+import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Locale;
@@ -51,48 +51,31 @@ class NewUserFormUtils {
     private static final PwmLogger LOGGER = PwmLogger.forClass(NewUserFormUtils.class);
 
 
-    static NewUserBean.NewUserForm readFromRequest(
+    static NewUserForm readFromRequest(
             final PwmRequest pwmRequest,
             final NewUserBean newUserBean
 
     )
             throws PwmDataValidationException, PwmUnrecoverableException
     {
-        final NewUserProfile newUserProfile = NewUserServlet.getNewUserProfile(pwmRequest);
-        final boolean promptForPassword = newUserProfile.readSettingAsBoolean(PwmSetting.NEWUSER_PROMPT_FOR_PASSWORD);
 
         final Locale userLocale = pwmRequest.getLocale();
         final List<FormConfiguration> newUserForm = NewUserServlet.getFormDefinition(pwmRequest);
         final Map<FormConfiguration, String> userFormValues = FormUtility.readFormValuesFromRequest(pwmRequest,
                 newUserForm, userLocale);
-        final PasswordData passwordData1;
-        final PasswordData passwordData2;
-        if (promptForPassword) {
-            passwordData1 = pwmRequest.readParameterAsPassword(NewUserServlet.FIELD_PASSWORD1);
-            passwordData2 = pwmRequest.readParameterAsPassword(NewUserServlet.FIELD_PASSWORD2);
-        } else {
-            final PwmPasswordPolicy pwmPasswordPolicy = newUserProfile.getNewUserPasswordPolicy(pwmRequest.getPwmApplication(), pwmRequest.getLocale());
-            final PasswordData password = RandomPasswordGenerator.createRandomPassword(pwmRequest.getSessionLabel(), pwmPasswordPolicy, pwmRequest.getPwmApplication());
-            passwordData1 = password;
-            passwordData2 = password;
-        }
-
-        final Map<String,String> mergedData = new LinkedHashMap<>(FormUtility.asStringMap(userFormValues));
-        if (newUserBean.getRemoteInputData() != null) {
-            mergedData.putAll(newUserBean.getRemoteInputData());
-        }
+        final PasswordData passwordData1 = pwmRequest.readParameterAsPassword(NewUserServlet.FIELD_PASSWORD1);
+        final PasswordData passwordData2 = pwmRequest.readParameterAsPassword(NewUserServlet.FIELD_PASSWORD2);
 
-        return new NewUserBean.NewUserForm(mergedData, passwordData1, passwordData2);
+        final NewUserProfile newUserProfile = NewUserServlet.getNewUserProfile(pwmRequest);
+        return injectRemoteValuesIntoForm(userFormValues, newUserBean.getRemoteInputData(), newUserProfile, passwordData1, passwordData2);
     }
 
-    static NewUserBean.NewUserForm readFromJsonRequest(
-            final PwmRequest pwmRequest
+    static NewUserForm readFromJsonRequest(
+            final PwmRequest pwmRequest,
+            final NewUserBean newUserBean
     )
             throws IOException, PwmUnrecoverableException, PwmDataValidationException
     {
-        final NewUserProfile newUserProfile = NewUserServlet.getNewUserProfile(pwmRequest);
-
-        final boolean promptForPassword = newUserProfile.readSettingAsBoolean(PwmSetting.NEWUSER_PROMPT_FOR_PASSWORD);
 
         final Locale userLocale = pwmRequest.getLocale();
         final List<FormConfiguration> newUserForm = NewUserServlet.getFormDefinition(pwmRequest);
@@ -100,24 +83,18 @@ class NewUserFormUtils {
         final Map<FormConfiguration, String> userFormValues = FormUtility.readFormValuesFromMap(jsonBodyMap,
                 newUserForm, userLocale);
 
-        final PasswordData passwordData1;
-        final PasswordData passwordData2;
-        if (promptForPassword) {
-            passwordData1 = jsonBodyMap.containsKey(NewUserServlet.FIELD_PASSWORD1) && !jsonBodyMap.get(
-                    NewUserServlet.FIELD_PASSWORD1).isEmpty()
-                    ? new PasswordData(jsonBodyMap.get(NewUserServlet.FIELD_PASSWORD1))
-                    : null;
-            passwordData2 = jsonBodyMap.containsKey(NewUserServlet.FIELD_PASSWORD2) && !jsonBodyMap.get(
-                    NewUserServlet.FIELD_PASSWORD2).isEmpty()
-                    ? new PasswordData(jsonBodyMap.get(NewUserServlet.FIELD_PASSWORD2))
-                    : null;
-        } else {
-            final PwmPasswordPolicy pwmPasswordPolicy = newUserProfile.getNewUserPasswordPolicy(pwmRequest.getPwmApplication(), pwmRequest.getLocale());
-            final PasswordData password = RandomPasswordGenerator.createRandomPassword(pwmRequest.getSessionLabel(), pwmPasswordPolicy, pwmRequest.getPwmApplication());
-            passwordData1 = password;
-            passwordData2 = password;
-        }
-        return new NewUserBean.NewUserForm(FormUtility.asStringMap(userFormValues), passwordData1, passwordData2);
+        final PasswordData passwordData1 = jsonBodyMap.containsKey(NewUserServlet.FIELD_PASSWORD1) && !jsonBodyMap.get(
+                NewUserServlet.FIELD_PASSWORD1).isEmpty()
+                ? new PasswordData(jsonBodyMap.get(NewUserServlet.FIELD_PASSWORD1))
+                : null;
+
+        final PasswordData passwordData2 = jsonBodyMap.containsKey(NewUserServlet.FIELD_PASSWORD2) && !jsonBodyMap.get(
+                NewUserServlet.FIELD_PASSWORD2).isEmpty()
+                ? new PasswordData(jsonBodyMap.get(NewUserServlet.FIELD_PASSWORD2))
+                : null;
+
+        final NewUserProfile newUserProfile = NewUserServlet.getNewUserProfile(pwmRequest);
+        return injectRemoteValuesIntoForm(userFormValues, newUserBean.getRemoteInputData(), newUserProfile, passwordData1, passwordData2);
     }
 
     static NewUserTokenData fromTokenPayload(
@@ -126,70 +103,40 @@ class NewUserFormUtils {
     )
             throws PwmOperationalException, PwmUnrecoverableException
     {
-        final Locale userLocale = pwmRequest.getLocale();
+        final SecureService secureService = pwmRequest.getPwmApplication().getSecureService();
 
         final Map<String, String> payloadMap = tokenPayload.getData();
 
-        final NewUserProfile newUserProfile;
-        {
-            final String profileID = payloadMap.get(NewUserServlet.TOKEN_PAYLOAD_ATTR);
-            payloadMap.remove(NewUserServlet.TOKEN_PAYLOAD_ATTR);
-            if (profileID == null || profileID.isEmpty()) {
-                // typically missing because issued with code before newuser profile existed, so assume  only profile
-                if (pwmRequest.getConfig().getNewUserProfiles().size() > 1) {
-                    throw new PwmOperationalException(PwmError.ERROR_TOKEN_INCORRECT, "token data missing reference to new user profileID");
-                }
-                newUserProfile = pwmRequest.getConfig().getNewUserProfiles().values().iterator().next();
-            } else {
-                if (!pwmRequest.getConfig().getNewUserProfiles().keySet().contains(profileID)) {
-                    throw new PwmOperationalException(PwmError.ERROR_TOKEN_INCORRECT, "token data references an invalid new user profileID");
-                }
-                newUserProfile = pwmRequest.getConfig().getNewUserProfiles().get(profileID);
-            }
+        if (!payloadMap.containsKey(NewUserServlet.TOKEN_PAYLOAD_ATTR)) {
+            throw new PwmOperationalException(new ErrorInformation(PwmError.ERROR_TOKEN_INCORRECT, "token is missing new user form data"));
         }
 
-        final List<FormConfiguration> newUserFormDefinition = newUserProfile.readSettingAsForm(PwmSetting.NEWUSER_FORM);
-        final Map<FormConfiguration, String> userFormValues = FormUtility.readFormValuesFromMap(payloadMap,
-                newUserFormDefinition, userLocale);
-        final PasswordData passwordData;
-        if (payloadMap.containsKey(NewUserServlet.FIELD_PASSWORD1)) {
-            final String passwordInToken = payloadMap.get(NewUserServlet.FIELD_PASSWORD1);
-            String decryptedPassword = passwordInToken;
-            try {
-                decryptedPassword = pwmRequest.getPwmApplication().getSecureService().decryptStringValue(passwordInToken);
-            } catch (PwmUnrecoverableException e) {
-                final boolean allowUnencryptedPassword = Boolean.parseBoolean(pwmRequest.getConfig().readAppProperty(AppProperty.NEWUSER_TOKEN_ALLOW_PLAIN_PW));
-                if (allowUnencryptedPassword && e.getError() == PwmError.ERROR_CRYPT_ERROR) {
-                    LOGGER.warn(pwmRequest, "error decrypting password in tokenPayload, will use raw password value: " + e.getMessage());
-                } else {
-                    throw e;
-                }
-            }
-            passwordData = new PasswordData(decryptedPassword);
-        } else {
-            passwordData = null;
-        }
-        final NewUserBean.NewUserForm newUserForm = new NewUserBean.NewUserForm(FormUtility.asStringMap(userFormValues), passwordData, passwordData);
-        return new NewUserTokenData(newUserProfile.getIdentifier(), newUserForm);
+        final String encryptedTokenData = payloadMap.get(NewUserServlet.TOKEN_PAYLOAD_ATTR);
+
+        return secureService.decryptObject(encryptedTokenData, NewUserTokenData.class);
     }
 
     static Map<String, String> toTokenPayload(
             final PwmRequest pwmRequest,
-            final NewUserBean.NewUserForm newUserForm
+            final NewUserBean newUserBean
     )
             throws PwmUnrecoverableException
     {
-        final Map<String, String> payloadMap = new LinkedHashMap<>();
-        payloadMap.put(NewUserServlet.TOKEN_PAYLOAD_ATTR, pwmRequest.getPwmApplication().getSessionStateService().getBean(pwmRequest, NewUserBean.class).getProfileID());
-        payloadMap.putAll(newUserForm.getFormData());
-        final String encryptedPassword = pwmRequest.getPwmApplication().getSecureService().encryptToString(
-                newUserForm.getNewUserPassword().getStringValue()
+
+        final NewUserTokenData newUserTokenData = new NewUserTokenData(
+                newUserBean.getProfileID(),
+                newUserBean.getNewUserForm(),
+                newUserBean.getRemoteInputData()
         );
-        payloadMap.put(NewUserServlet.FIELD_PASSWORD1, encryptedPassword);
+
+        final SecureService secureService = pwmRequest.getPwmApplication().getSecureService();
+        final String encodedTokenData = secureService.encryptObjectToString(newUserTokenData);
+        final Map<String, String> payloadMap = new HashMap<>();
+        payloadMap.put(NewUserServlet.TOKEN_PAYLOAD_ATTR, encodedTokenData);
         return payloadMap;
     }
 
-    static Map<String,String> getLdapDataFromNewUserForm(final NewUserProfile newUserProfile, final NewUserBean.NewUserForm newUserForm) {
+    static Map<String,String> getLdapDataFromNewUserForm(final NewUserProfile newUserProfile, final NewUserForm newUserForm) {
         final Map<String,String> ldapData = new LinkedHashMap<>();
         final List<FormConfiguration> formConfigurations = newUserProfile.readSettingAsForm(PwmSetting.NEWUSER_FORM);
         for (final FormConfiguration formConfiguration : formConfigurations) {
@@ -201,4 +148,29 @@ class NewUserFormUtils {
         }
         return ldapData;
     }
+
+    static NewUserForm injectRemoteValuesIntoForm(
+            final Map<FormConfiguration, String> userFormValues,
+            final Map<String,String> injectedValues,
+            final NewUserProfile newUserProfile,
+            final PasswordData passwordData1,
+            final PasswordData passwordData2
+    ) {
+        final Map<String,String> newFormValues = new HashMap<>();
+        newFormValues.putAll(FormUtility.asStringMap(userFormValues));
+
+        final List<FormConfiguration> formConfigurations = newUserProfile.readSettingAsForm(PwmSetting.NEWUSER_FORM);
+        if (injectedValues != null) {
+            for (final FormConfiguration formConfiguration : formConfigurations) {
+                final String name = formConfiguration.getName();
+                if (formConfiguration.isReadonly()
+                        || !newFormValues.containsKey(name) && injectedValues.containsKey(name))
+                {
+                    newFormValues.put(formConfiguration.getName(), injectedValues.get(formConfiguration.getName()));
+                }
+            }
+        }
+
+        return new NewUserForm(newFormValues, passwordData1, passwordData2);
+    }
 }

+ 37 - 18
src/main/java/password/pwm/http/servlet/newuser/NewUserServlet.java

@@ -72,6 +72,7 @@ import java.time.Instant;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Locale;
@@ -97,7 +98,7 @@ public class NewUserServlet extends ControlledPwmServlet {
 
     static final String FIELD_PASSWORD1 = "password1";
     static final String FIELD_PASSWORD2 = "password2";
-    static final String TOKEN_PAYLOAD_ATTR = "_______profileID";
+    static final String TOKEN_PAYLOAD_ATTR = "p";
 
     public enum NewUserAction implements AbstractPwmServlet.ProcessAction {
         profileChoice(HttpMethod.POST, HttpMethod.POST),
@@ -148,8 +149,8 @@ public class NewUserServlet extends ControlledPwmServlet {
 
         final String signedFormData = pwmRequest.readParameterAsString("signedForm", PwmHttpRequestWrapper.Flag.BypassValidation);
         if (!StringUtil.isEmpty(signedFormData)) {
-            LOGGER.trace("detected signedForm parameter in request, will read and place in bean.");
             final Map<String,String> jsonForm = RestSigningServer.readSignedFormValue(pwmApplication, signedFormData);
+            LOGGER.trace("detected signedForm parameter in request, will read and place in bean; keys=" + JsonUtil.serializeCollection(jsonForm.keySet()));
             newUserBean.setRemoteInputData(jsonForm);
         }
 
@@ -308,7 +309,8 @@ public class NewUserServlet extends ControlledPwmServlet {
         final Locale locale = pwmRequest.getLocale();
 
         try {
-            final NewUserBean.NewUserForm newUserForm = NewUserFormUtils.readFromJsonRequest(pwmRequest);
+            final NewUserBean newUserBean = getNewUserBean(pwmRequest);
+            final NewUserForm newUserForm = NewUserFormUtils.readFromJsonRequest(pwmRequest, newUserBean);
             PasswordUtility.PasswordCheckInfo passwordCheckInfo = verifyForm(pwmRequest, newUserForm, true);
             if (passwordCheckInfo.isPassed() && passwordCheckInfo.getMatch() == PasswordUtility.PasswordCheckInfo.MatchStatus.MATCH) {
                 passwordCheckInfo = new PasswordUtility.PasswordCheckInfo(
@@ -336,7 +338,7 @@ public class NewUserServlet extends ControlledPwmServlet {
 
     static PasswordUtility.PasswordCheckInfo verifyForm(
             final PwmRequest pwmRequest,
-            final NewUserBean.NewUserForm newUserForm,
+            final NewUserForm newUserForm,
             final boolean allowResultCaching
     )
             throws PwmDataValidationException, PwmUnrecoverableException, ChaiUnavailableException
@@ -359,15 +361,22 @@ public class NewUserServlet extends ControlledPwmServlet {
                 .cachedPasswordRuleAttributes(FormUtility.asStringMap(formValueData))
                 .passwordPolicy(newUserProfile.getNewUserPasswordPolicy(pwmApplication, locale))
                 .build();
-        return PasswordUtility.checkEnteredPassword(
-                pwmApplication,
-                locale,
-                null,
-                uiBean,
-                null,
-                newUserForm.getNewUserPassword(),
-                newUserForm.getConfirmPassword()
-        );
+
+        final boolean promptForPassword = newUserProfile.readSettingAsBoolean(PwmSetting.NEWUSER_PROMPT_FOR_PASSWORD);
+
+        if (promptForPassword) {
+            return PasswordUtility.checkEnteredPassword(
+                    pwmApplication,
+                    locale,
+                    null,
+                    uiBean,
+                    null,
+                    newUserForm.getNewUserPassword(),
+                    newUserForm.getConfirmPassword()
+            );
+        }
+
+        return new PasswordUtility.PasswordCheckInfo(null, true, 0, PasswordUtility.PasswordCheckInfo.MatchStatus.MATCH, 0);
     }
 
     @ActionHandler(action = "enterCode")
@@ -391,7 +400,7 @@ public class NewUserServlet extends ControlledPwmServlet {
                 final NewUserBean newUserBean = getNewUserBean(pwmRequest);
                 final NewUserTokenData newUserTokenData = NewUserFormUtils.fromTokenPayload(pwmRequest, tokenPayload);
                 newUserBean.setProfileID(newUserTokenData.getProfileID());
-                final NewUserBean.NewUserForm newUserFormFromToken = newUserTokenData.getFormData();
+                final NewUserForm newUserFormFromToken = newUserTokenData.getFormData();
                 if (password.pwm.svc.token.TokenType.NEWUSER_EMAIL.matchesName(tokenPayload.getName())) {
                     LOGGER.debug(pwmRequest, "email token passed");
 
@@ -402,6 +411,7 @@ public class NewUserServlet extends ControlledPwmServlet {
                         throw e;
                     }
 
+                    newUserBean.setRemoteInputData(newUserTokenData.getInjectionData());
                     newUserBean.setNewUserForm(newUserFormFromToken);
                     newUserBean.setFormPassed(true);
                     newUserBean.getTokenVerificationProgress().getPassedTokens().add(TokenVerificationProgress.TokenChannel.EMAIL);
@@ -479,7 +489,7 @@ public class NewUserServlet extends ControlledPwmServlet {
         newUserBean.setNewUserForm(null);
 
         try {
-            final NewUserBean.NewUserForm newUserForm = NewUserFormUtils.readFromRequest(pwmRequest, newUserBean);
+            final NewUserForm newUserForm = NewUserFormUtils.readFromRequest(pwmRequest, newUserBean);
             final PasswordUtility.PasswordCheckInfo passwordCheckInfo = verifyForm(pwmRequest, newUserForm, true);
             NewUserUtils.passwordCheckInfoToException(passwordCheckInfo);
             newUserBean.setNewUserForm(newUserForm);
@@ -616,10 +626,20 @@ public class NewUserServlet extends ControlledPwmServlet {
     private void forwardToFormPage(final PwmRequest pwmRequest, final NewUserBean newUserBean)
             throws ServletException, PwmUnrecoverableException, IOException
     {
-        final List<FormConfiguration> formConfiguration = getFormDefinition(pwmRequest);
+        final List<FormConfiguration> formConfigurations = getFormDefinition(pwmRequest);
         final NewUserProfile newUserProfile = getNewUserProfile(pwmRequest);
         final boolean promptForPassword = newUserProfile.readSettingAsBoolean(PwmSetting.NEWUSER_PROMPT_FOR_PASSWORD);
-        pwmRequest.addFormInfoToRequestAttr(formConfiguration, null, false, promptForPassword);
+        final Map<FormConfiguration,String> formData = new HashMap<>();
+        if (newUserBean.getRemoteInputData() != null) {
+            final Map<String,String> remoteData = newUserBean.getRemoteInputData();
+            for (final FormConfiguration formConfiguration : formConfigurations) {
+                if (remoteData.containsKey(formConfiguration.getName())) {
+                    formData.put(formConfiguration, remoteData.get(formConfiguration.getName()));
+                }
+            }
+        }
+
+        pwmRequest.addFormInfoToRequestAttr(formConfigurations, formData, false, promptForPassword);
 
         {
             final boolean showBack = !newUserBean.isUrlSpecifiedProfile()
@@ -629,5 +649,4 @@ public class NewUserServlet extends ControlledPwmServlet {
 
         pwmRequest.forwardToJsp(JspUrl.NEW_USER);
     }
-
 }

+ 14 - 7
src/main/java/password/pwm/http/servlet/newuser/NewUserTokenData.java

@@ -22,24 +22,31 @@
 
 package password.pwm.http.servlet.newuser;
 
-import password.pwm.http.bean.NewUserBean;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
 
 import java.io.Serializable;
+import java.util.Map;
 
+@Getter
+@AllArgsConstructor
 class NewUserTokenData implements Serializable {
+
+    @SerializedName("id")
     private String profileID;
-    private NewUserBean.NewUserForm formData;
 
-    NewUserTokenData(final String profileID, final NewUserBean.NewUserForm formData) {
-        this.profileID = profileID;
-        this.formData = formData;
-    }
+    @SerializedName("f")
+    private NewUserForm formData;
+
+    @SerializedName("i")
+    private Map<String,String> injectionData;
 
     public String getProfileID() {
         return profileID;
     }
 
-    public NewUserBean.NewUserForm getFormData() {
+    public NewUserForm getFormData() {
         return formData;
     }
 }

+ 17 - 7
src/main/java/password/pwm/http/servlet/newuser/NewUserUtils.java

@@ -43,6 +43,7 @@ import password.pwm.config.PwmSetting;
 import password.pwm.config.option.TokenStorageMethod;
 import password.pwm.config.profile.LdapProfile;
 import password.pwm.config.profile.NewUserProfile;
+import password.pwm.config.profile.PwmPasswordPolicy;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmOperationalException;
@@ -80,7 +81,7 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
-public class NewUserUtils {
+class NewUserUtils {
     private static PwmLogger LOGGER = password.pwm.util.logging.PwmLogger.forClass(NewUserUtils.class);
 
     private NewUserUtils() {
@@ -102,7 +103,7 @@ public class NewUserUtils {
     }
 
     static void createUser(
-            final NewUserBean.NewUserForm newUserForm,
+            final NewUserForm newUserForm,
             final PwmRequest pwmRequest,
             final String newUserDN
     )
@@ -124,7 +125,17 @@ public class NewUserUtils {
         }
 
         NewUserUtils.LOGGER.debug(pwmSession, "beginning createUser process for " + newUserDN);
-        final PasswordData userPassword = newUserForm.getNewUserPassword();
+
+        final NewUserProfile newUserProfile = NewUserServlet.getNewUserProfile(pwmRequest);
+        final boolean promptForPassword = newUserProfile.readSettingAsBoolean(PwmSetting.NEWUSER_PROMPT_FOR_PASSWORD);
+
+        final PasswordData userPassword;
+        if (promptForPassword) {
+            userPassword = newUserForm.getNewUserPassword();
+        } else {
+            final PwmPasswordPolicy pwmPasswordPolicy = newUserProfile.getNewUserPasswordPolicy(pwmRequest.getPwmApplication(), pwmRequest.getLocale());
+            userPassword = RandomPasswordGenerator.createRandomPassword(pwmRequest.getSessionLabel(), pwmPasswordPolicy, pwmRequest.getPwmApplication());
+        }
 
         // set up the user creation attributes
         final Map<String, String> createAttributes = NewUserFormUtils.getLdapDataFromNewUserForm(NewUserServlet.getNewUserProfile(pwmRequest), newUserForm);
@@ -152,7 +163,6 @@ public class NewUserUtils {
         }
 
         final ChaiUser theUser = ChaiFactory.createChaiUser(newUserDN, chaiProvider);
-        final NewUserProfile newUserProfile = NewUserServlet.getNewUserProfile(pwmRequest);
 
         final boolean useTempPw;
         {
@@ -293,7 +303,7 @@ public class NewUserUtils {
 
     static String determineUserDN(
             final PwmRequest pwmRequest,
-            final NewUserBean.NewUserForm formValues
+            final NewUserForm formValues
     )
             throws PwmUnrecoverableException, ChaiUnavailableException
     {
@@ -405,7 +415,7 @@ public class NewUserUtils {
     static MacroMachine createMacroMachineForNewUser(
             final PwmApplication pwmApplication,
             final SessionLabel sessionLabel,
-            final NewUserBean.NewUserForm newUserForm
+            final NewUserForm newUserForm
     )
             throws PwmUnrecoverableException
     {
@@ -445,7 +455,7 @@ public class NewUserUtils {
         }
 
         final Configuration config = pwmApplication.getConfig();
-        final Map<String, String> tokenPayloadMap = NewUserFormUtils.toTokenPayload(pwmRequest, newUserBean.getNewUserForm());
+        final Map<String, String> tokenPayloadMap = NewUserFormUtils.toTokenPayload(pwmRequest, newUserBean);
         final MacroMachine macroMachine = createMacroMachineForNewUser(pwmApplication, pwmRequest.getSessionLabel(), newUserBean.getNewUserForm());
 
         switch (tokenType) {

+ 4 - 13
src/main/java/password/pwm/svc/event/AuditService.java

@@ -214,7 +214,7 @@ public class AuditService implements PwmService {
         return userHistoryStore.readUserHistory(userInfoBean);
     }
 
-    protected void sendAsEmail(final AuditRecord record)
+    private void sendAsEmail(final AuditRecord record)
             throws PwmUnrecoverableException
     {
         if (record == null || record.getEventCode() == null) {
@@ -227,14 +227,14 @@ public class AuditService implements PwmService {
         switch (record.getEventCode().getType()) {
             case SYSTEM:
                 for (final String toAddress : settings.getSystemEmailAddresses()) {
-                    sendAsEmail(pwmApplication, null, record, toAddress, settings.getAlertFromAddress());
+                    sendAsEmail(pwmApplication, record, toAddress, settings.getAlertFromAddress());
                 }
                 break;
 
             case USER:
             case HELPDESK:
                 for (final String toAddress : settings.getUserEmailAddresses()) {
-                    sendAsEmail(pwmApplication, null, record, toAddress, settings.getAlertFromAddress());
+                    sendAsEmail(pwmApplication, record, toAddress, settings.getAlertFromAddress());
                 }
                 break;
 
@@ -246,7 +246,6 @@ public class AuditService implements PwmService {
 
     private static void sendAsEmail(
             final PwmApplication pwmApplication,
-            final SessionLabel sessionLabel,
             final AuditRecord record,
             final String toAddress,
             final String fromAddress
@@ -254,7 +253,7 @@ public class AuditService implements PwmService {
     )
             throws PwmUnrecoverableException
     {
-        final MacroMachine macroMachine = MacroMachine.forNonUserSpecific(pwmApplication, sessionLabel);
+        final MacroMachine macroMachine = MacroMachine.forNonUserSpecific(pwmApplication, SessionLabel.AUDITING_SESSION_LABEL);
 
         String subject = macroMachine.expandMacros(pwmApplication.getConfig().readAppProperty(AppProperty.AUDIT_EVENTS_EMAILSUBJECT));
         subject = subject.replace("%EVENT%", record.getEventCode().getLocalizedString(pwmApplication.getConfig(), PwmConstants.DEFAULT_LOCALE));
@@ -270,14 +269,6 @@ public class AuditService implements PwmService {
         pwmApplication.getEmailQueue().submitEmail(emailItem, null, macroMachine);
     }
 
-    public int vaultSize() {
-        if (status != STATUS.OPEN || auditVault == null) {
-            return -1;
-        }
-
-        return auditVault.size();
-    }
-
     public Instant eldestVaultRecord() {
         if (status != STATUS.OPEN || auditVault == null) {
             return null;

+ 1 - 1
src/main/java/password/pwm/svc/event/SyslogAuditService.java

@@ -96,7 +96,7 @@ public class SyslogAuditService {
             syslogInstance = makeSyslogInstance(syslogConfig);
             LOGGER.trace("queued service running for " + syslogConfig);
         } catch (IllegalArgumentException e) {
-            LOGGER.error("e9rror parsing syslog configuration for '" + syslogConfigString + "', error: " + e.getMessage());
+            LOGGER.error("error parsing syslog configuration for '" + syslogConfigString + "', error: " + e.getMessage());
         }
 
         final WorkQueueProcessor.Settings settings = WorkQueueProcessor.Settings.builder()

+ 4 - 3
src/main/java/password/pwm/ws/server/rest/RestSigningServer.java

@@ -24,6 +24,7 @@ package password.pwm.ws.server.rest;
 
 import lombok.AllArgsConstructor;
 import lombok.Getter;
+import password.pwm.AppProperty;
 import password.pwm.PwmApplication;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
@@ -92,11 +93,12 @@ public class RestSigningServer extends AbstractRestServer {
 
     public static Map<String,String> readSignedFormValue(final PwmApplication pwmApplication, final String input) throws PwmUnrecoverableException
     {
-        final TimeDuration MAX_FORM_AGE = new TimeDuration(5, TimeUnit.MINUTES);
+        final Integer maxAgeSeconds = Integer.parseInt(pwmApplication.getConfig().readAppProperty(AppProperty.WS_REST_SERVER_SIGNING_FORM_TIMEOUT_SECONDS));
+        final TimeDuration maxAge = new TimeDuration(maxAgeSeconds, TimeUnit.SECONDS);
         final SignedFormData signedFormData = pwmApplication.getSecureService().decryptObject(input, SignedFormData.class);
         if (signedFormData != null) {
             if (signedFormData.getTimestamp() != null) {
-                if (TimeDuration.fromCurrent(signedFormData.getTimestamp()).isLongerThan(MAX_FORM_AGE)) {
+                if (TimeDuration.fromCurrent(signedFormData.getTimestamp()).isLongerThan(maxAge)) {
                     throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_SECURITY_VIOLATION,"signedForm data is too old"));
                 }
 
@@ -112,5 +114,4 @@ public class RestSigningServer extends AbstractRestServer {
         private Instant timestamp;
         private Map<String,String> formData;
     }
-
 }

+ 1 - 0
src/main/resources/password/pwm/AppProperty.properties

@@ -269,4 +269,5 @@ wordlist.builtin.path=/WEB-INF/wordlist.zip
 wordlist.maxCharLength=64
 wordlist.minCharLength=2
 ws.restClient.pwRule.haltOnError=true
+ws.restServer.signing.form.timeoutSeconds=120
 password.policy.allowMacroInRegexSetting=true

+ 1 - 0
src/main/resources/password/pwm/config/PwmSetting.xml

@@ -2527,6 +2527,7 @@
         <ldapPermission actor="proxy" access="write"/>
         <flag>Form_ShowUniqueOption</flag>
         <flag>Form_ShowRequiredOption</flag>
+        <flag>Form_ShowReadOnlyOption</flag>
         <default>
             <value>{"name":"mail","minimumLength":1,"maximumLength":64,"type":"email","required":true,"confirmationRequired":false,"readonly":false,"unique":true,"labels":{"":"Email Address"},"regexErrors":{"":"Email Address has invalid characters"},"description":{"":""},"placeholder":"username@example.com","selectOptions":{},regex:"^[a-zA-Z0-9 .,'@]*$"}</value>
             <value>{"name":"givenName","minimumLength":1,"maximumLength":64,"type":"text","required":true,"confirmationRequired":false,"readonly":false,"labels":{"":"First Name"},"regexErrors":{"":""},"description":{"":""},"selectOptions":{},regex:"^[a-zA-Z0-9 .,'@]*$"}</value>

+ 1 - 1
src/main/resources/password/pwm/i18n/Admin.properties

@@ -241,7 +241,7 @@ Statistic_Description.HelpdeskTokenSent=Number of Help Desk verification tokens
 Statistic_Label.HelpdeskUnlock=Help Desk Unlocks
 Statistic_Description.HelpdeskUnlock=Number of Help Desk unlock user events.
 Statistic_Label.HelpdeskVerifyOTP=Help Desk OTP Verifications
-Statistic_Description.HelpdeskVerifyOTP=Number of successful Help Desk OPT verification user events.
+Statistic_Description.HelpdeskVerifyOTP=Number of successful Help Desk OTP verification user events.
 Statistic_Label.RestStatus=WebService Status Calls
 Statistic_Description.RestStatus=Number of external web service calls to the /status REST interface.
 Statistic_Label.RestCheckPassword=WebService Check Password Calls

+ 4 - 0
src/main/webapp/WEB-INF/jsp/fragment/form.jsp

@@ -13,6 +13,7 @@
 <%@ page import="java.util.Map" %>
 <%@ page import="password.pwm.http.tag.value.PwmValue" %>
 <%@ page import="password.pwm.http.PwmRequestAttribute" %>
+<%@ page import="java.util.Collections" %>
 
 <%--
   ~ Password Management Servlets (PWM)
@@ -50,6 +51,9 @@
     final boolean forceReadOnly = (Boolean)JspUtility.getAttribute(pageContext, PwmRequestAttribute.FormReadOnly);
     final boolean showPasswordFields = (Boolean)JspUtility.getAttribute(pageContext, PwmRequestAttribute.FormShowPasswordFields);
     final Map<FormConfiguration,String> formDataMap = (Map<FormConfiguration,String>)JspUtility.getAttribute(pageContext, PwmRequestAttribute.FormData);
+    final Map<String,String> initalValues = (JspUtility.getAttribute(pageContext, PwmRequestAttribute.FormInitialValues) != null)
+            ? (Map<String,String>)JspUtility.getAttribute(pageContext, PwmRequestAttribute.FormInitialValues)
+            : Collections.<String,String>emptyMap();
 
     final PwmApplication pwmApplication = formPwmRequest.getPwmApplication();
     final Locale formLocale = formPwmRequest.getLocale();