Browse Source

add forgotten password agreement page

Jason Rivard 4 năm trước cách đây
mục cha
commit
6742f0c71b

+ 2 - 0
server/src/main/java/password/pwm/config/PwmSetting.java

@@ -811,6 +811,8 @@ public enum PwmSetting
             "recovery.minimumPasswordLifetimeOptions", PwmSettingSyntax.SELECT, PwmSettingCategory.RECOVERY_OPTIONS ),
             "recovery.minimumPasswordLifetimeOptions", PwmSettingSyntax.SELECT, PwmSettingCategory.RECOVERY_OPTIONS ),
     RECOVERY_POST_ACTIONS(
     RECOVERY_POST_ACTIONS(
             "recovery.postActions", PwmSettingSyntax.ACTION, PwmSettingCategory.RECOVERY_OPTIONS ),
             "recovery.postActions", PwmSettingSyntax.ACTION, PwmSettingCategory.RECOVERY_OPTIONS ),
+    RECOVERY_AGREEMENT_MESSAGE(
+            "recovery.changeAgreement", PwmSettingSyntax.LOCALIZED_TEXT_AREA, PwmSettingCategory.RECOVERY_OPTIONS ),
 
 
 
 
     // recovery oauth
     // recovery oauth

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

@@ -50,6 +50,7 @@ public enum JspUrl
     PASSWORD_AGREEMENT( "changepassword-agreement.jsp" ),
     PASSWORD_AGREEMENT( "changepassword-agreement.jsp" ),
     PASSWORD_COMPLETE( "changepassword-complete.jsp" ),
     PASSWORD_COMPLETE( "changepassword-complete.jsp" ),
     PASSWORD_WARN( "changepassword-warn.jsp" ),
     PASSWORD_WARN( "changepassword-warn.jsp" ),
+    RECOVER_USER_AGREEMENT( "forgottenpassword-agreement.jsp" ),
     RECOVER_PASSWORD_SEARCH( "forgottenpassword-search.jsp" ),
     RECOVER_PASSWORD_SEARCH( "forgottenpassword-search.jsp" ),
     RECOVER_PASSWORD_RESPONSES( "forgottenpassword-responses.jsp" ),
     RECOVER_PASSWORD_RESPONSES( "forgottenpassword-responses.jsp" ),
     RECOVER_PASSWORD_ATTRIBUTES( "forgottenpassword-attributes.jsp" ),
     RECOVER_PASSWORD_ATTRIBUTES( "forgottenpassword-attributes.jsp" ),

+ 3 - 0
server/src/main/java/password/pwm/http/bean/ForgottenPasswordBean.java

@@ -75,6 +75,9 @@ public class ForgottenPasswordBean extends PwmSessionBean
     @SerializedName( "b" )
     @SerializedName( "b" )
     private boolean bogusUser;
     private boolean bogusUser;
 
 
+    @SerializedName( "g" )
+    private boolean agreementPassed;
+
     @SerializedName( "fp" )
     @SerializedName( "fp" )
     private String forgottenPasswordProfileID;
     private String forgottenPasswordProfileID;
 
 

+ 38 - 2
server/src/main/java/password/pwm/http/servlet/forgottenpw/ForgottenPasswordServlet.java

@@ -70,6 +70,8 @@ import password.pwm.ldap.auth.SessionAuthenticator;
 import password.pwm.ldap.search.SearchConfiguration;
 import password.pwm.ldap.search.SearchConfiguration;
 import password.pwm.ldap.search.UserSearchEngine;
 import password.pwm.ldap.search.UserSearchEngine;
 import password.pwm.svc.event.AuditEvent;
 import password.pwm.svc.event.AuditEvent;
+import password.pwm.svc.event.AuditRecord;
+import password.pwm.svc.event.AuditRecordFactory;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.StatisticsManager;
 import password.pwm.svc.stats.StatisticsManager;
 import password.pwm.svc.token.TokenPayload;
 import password.pwm.svc.token.TokenPayload;
@@ -80,11 +82,13 @@ import password.pwm.util.CaptchaUtility;
 import password.pwm.util.form.FormUtility;
 import password.pwm.util.form.FormUtility;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.JsonUtil;
+import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
-import password.pwm.util.password.PasswordUtility;
+import password.pwm.util.macro.MacroMachine;
 import password.pwm.util.operations.cr.NMASCrOperator;
 import password.pwm.util.operations.cr.NMASCrOperator;
 import password.pwm.util.operations.otp.OTPUserRecord;
 import password.pwm.util.operations.otp.OTPUserRecord;
+import password.pwm.util.password.PasswordUtility;
 import password.pwm.ws.server.RestResultBean;
 import password.pwm.ws.server.RestResultBean;
 
 
 import javax.servlet.ServletException;
 import javax.servlet.ServletException;
@@ -133,7 +137,8 @@ public class ForgottenPasswordServlet extends ControlledPwmServlet
         verificationChoice( HttpMethod.POST ),
         verificationChoice( HttpMethod.POST ),
         enterRemoteResponse( HttpMethod.POST ),
         enterRemoteResponse( HttpMethod.POST ),
         oauthReturn( HttpMethod.GET ),
         oauthReturn( HttpMethod.GET ),
-        resendToken( HttpMethod.POST ),;
+        resendToken( HttpMethod.POST ),
+        agree( HttpMethod.POST ),;
 
 
         private final Collection<HttpMethod> method;
         private final Collection<HttpMethod> method;
 
 
@@ -918,6 +923,27 @@ public class ForgottenPasswordServlet extends ControlledPwmServlet
         return ProcessStatus.Continue;
         return ProcessStatus.Continue;
     }
     }
 
 
+    @ActionHandler( action = "agree" )
+    ProcessStatus processAgreeAction( final PwmRequest pwmRequest )
+            throws PwmUnrecoverableException
+    {
+        final ForgottenPasswordBean forgottenPasswordBean = forgottenPasswordBean( pwmRequest );
+
+        LOGGER.debug( pwmRequest, () -> "user accepted forgotten password agreement" );
+        if ( !forgottenPasswordBean.isAgreementPassed() )
+        {
+            forgottenPasswordBean.setAgreementPassed( true );
+            final AuditRecord auditRecord = new AuditRecordFactory( pwmRequest ).createUserAuditRecord(
+                    AuditEvent.AGREEMENT_PASSED,
+                    pwmRequest.getUserInfoIfLoggedIn(),
+                    pwmRequest.getLabel(),
+                    "ForgottenPassword"
+            );
+            pwmRequest.getPwmApplication().getAuditManager().submit( auditRecord );
+        }
+
+        return ProcessStatus.Continue;
+    }
 
 
     @Override
     @Override
     @SuppressWarnings( "checkstyle:MethodLength" )
     @SuppressWarnings( "checkstyle:MethodLength" )
@@ -974,6 +1000,16 @@ public class ForgottenPasswordServlet extends ControlledPwmServlet
             }
             }
         }
         }
 
 
+        final String agreementMsg = forgottenPasswordProfile.readSettingAsLocalizedString( PwmSetting.RECOVERY_AGREEMENT_MESSAGE, pwmRequest.getLocale() );
+        if ( !StringUtil.isEmpty( agreementMsg ) && !forgottenPasswordBean.isAgreementPassed() )
+        {
+            final MacroMachine macroMachine = pwmRequest.getPwmSession().getSessionManager().getMacroMachine();
+            final String expandedText = macroMachine.expandMacros( agreementMsg );
+            pwmRequest.setAttribute( PwmRequestAttribute.AgreementText, expandedText );
+            pwmRequest.forwardToJsp( JspUrl.RECOVER_USER_AGREEMENT );
+            return;
+        }
+
         // dispatch required auth methods.
         // dispatch required auth methods.
         for ( final IdentityVerificationMethod method : recoveryFlags.getRequiredAuthMethods() )
         for ( final IdentityVerificationMethod method : recoveryFlags.getRequiredAuthMethods() )
         {
         {

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

@@ -2630,6 +2630,10 @@
             <value/>
             <value/>
         </default>
         </default>
     </setting>
     </setting>
+    <setting hidden="false" key="recovery.changeAgreement" level="1">
+        <flag>MacroSupport</flag>
+        <default/>
+    </setting>
     <setting hidden="false" key="recovery.allowWhenLocked" level="2">
     <setting hidden="false" key="recovery.allowWhenLocked" level="2">
         <default>
         <default>
             <value>false</value>
             <value>false</value>

+ 2 - 0
server/src/main/resources/password/pwm/i18n/PwmSetting.properties

@@ -659,6 +659,7 @@ Setting_Description_pwNotify.job.offSet=GMT job offset time.  The expiration not
 Setting_Description_recovery.action=Add actions to take when the user completes the forgotten password process.
 Setting_Description_recovery.action=Add actions to take when the user completes the forgotten password process.
 Setting_Description_recovery.allowWhenLocked=Enable this option to allow users to use the forgotten password feature when the account is intruder locked in LDAP.  This feature is not available when a user is using NMAS stored responses.
 Setting_Description_recovery.allowWhenLocked=Enable this option to allow users to use the forgotten password feature when the account is intruder locked in LDAP.  This feature is not available when a user is using NMAS stored responses.
 Setting_Description_recovery.bogus.user.enable=Enable this option to have forgotten password act as though invalid user searches are valid, and present such users with a bogus forgotten password policy.  This can help prevent username discovery.
 Setting_Description_recovery.bogus.user.enable=Enable this option to have forgotten password act as though invalid user searches are valid, and present such users with a bogus forgotten password policy.  This can help prevent username discovery.
+Setting_Description_recovery.changeAgreement=<p>Specify a message to display to users before allowing them to recover their forgotten passwords. If blank, @PwmAppName@ does not display the agreement page to the users. This message can include HTML tags.</p> <p>This setting can use macros.  For more information about macros, see the "View" menu "Show Macro Help".</p>
 Setting_Description_recovery.enable=Enable this option to have the forgotten password recovery available to users.
 Setting_Description_recovery.enable=Enable this option to have the forgotten password recovery available to users.
 Setting_Description_recovery.form=Specify the form fields for the activate user module. @PwmAppName@ requires the users to enter each attribute. Ideally, @PwmAppName@ requires the users to enter some personal data that is not publicly known.
 Setting_Description_recovery.form=Specify the form fields for the activate user module. @PwmAppName@ requires the users to enter each attribute. Ideally, @PwmAppName@ requires the users to enter some personal data that is not publicly known.
 Setting_Description_recovery.minimumPasswordLifetimeOptions=Options to control behavior when a user attempts to use the forgotten password module while their password is within the minimum password policy lifetime window of their effective password policy.  These options are only relevant if the user has an effective minimum password lifetime as part of their password policy.
 Setting_Description_recovery.minimumPasswordLifetimeOptions=Options to control behavior when a user attempts to use the forgotten password module while their password is within the minimum password policy lifetime window of their effective password policy.  These options are only relevant if the user has an effective minimum password lifetime as part of their password policy.
@@ -1192,6 +1193,7 @@ Setting_Label_pwNotify.job.offSet=Job Offset
 Setting_Label_recovery.action=Forgotten Password Recovery Mode
 Setting_Label_recovery.action=Forgotten Password Recovery Mode
 Setting_Label_recovery.allowWhenLocked=Allow Forgotten Password when Locked
 Setting_Label_recovery.allowWhenLocked=Allow Forgotten Password when Locked
 Setting_Label_recovery.bogus.user.enable=Enable Bogus User Policy
 Setting_Label_recovery.bogus.user.enable=Enable Bogus User Policy
+Setting_Label_recovery.changeAgreement=Agreement Message
 Setting_Label_recovery.enable=Enable Forgotten Password
 Setting_Label_recovery.enable=Enable Forgotten Password
 Setting_Label_recovery.form=Forgotten Password User Search Form
 Setting_Label_recovery.form=Forgotten Password User Search Form
 Setting_Label_recovery.minimumPasswordLifetimeOptions=Minimum Password Lifetime Options
 Setting_Label_recovery.minimumPasswordLifetimeOptions=Minimum Password Lifetime Options

+ 93 - 0
webapp/src/main/webapp/WEB-INF/jsp/forgottenpassword-agreement.jsp

@@ -0,0 +1,93 @@
+<%--
+ ~ Password Management Servlets (PWM)
+ ~ http://www.pwm-project.org
+ ~
+ ~ Copyright (c) 2006-2009 Novell, Inc.
+ ~ Copyright (c) 2009-2020 The PWM Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~     http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+--%>
+<%--
+       THIS FILE IS NOT INTENDED FOR END USER MODIFICATION.
+       See the README.TXT file in WEB-INF/jsp before making changes.
+--%>
+
+
+<%@ page import="password.pwm.http.tag.conditional.PwmIfTest" %>
+
+<!DOCTYPE html>
+<%@ page language="java" session="true" isThreadSafe="true" contentType="text/html" %>
+<%@ taglib uri="pwm" prefix="pwm" %>
+<html lang="<pwm:value name="<%=PwmValue.localeCode%>"/>" dir="<pwm:value name="<%=PwmValue.localeDir%>"/>">
+<%@ include file="fragment/header.jsp" %>
+<body class="nihilo">
+<div id="wrapper">
+    <% JspUtility.setFlag(pageContext, PwmRequestFlag.HIDE_HEADER_BUTTONS); %>
+    <jsp:include page="fragment/header-body.jsp">
+        <jsp:param name="pwm.PageName" value="Title_ForgottenPassword"/>
+    </jsp:include>
+    <div id="centerbody">
+        <h1 id="page-content-title"><pwm:display key="Title_ForgottenPassword" displayIfMissing="true"/></h1>
+        <%@ include file="fragment/message.jsp" %>
+        <% final String expandedText = (String)JspUtility.getAttribute( pageContext, PwmRequestAttribute.AgreementText ); %>
+        <br/><br/>
+        <div id="agreementText" class="agreementText"><%= expandedText %></div>
+        <div class="buttonbar">
+            <form action="<pwm:current-url/>" method="post" enctype="application/x-www-form-urlencoded" class="pwm-form" style="display: inline;">
+                <%-- remove the next line to remove the "I Agree" checkbox --%>
+                <label class="checkboxWrapper">
+                    <input type="checkbox" id="agreeCheckBox"/>
+                    <pwm:display key="Button_Agree"/>
+                </label>
+                <br/><br/>
+                <input type="hidden" name="processAction" value="agree"/>
+                <button type="submit" name="button" class="btn" id="submitBtn">
+                    <pwm:if test="<%=PwmIfTest.showIcons%>"><span class="btn-icon pwm-icon pwm-icon-forward"></span></pwm:if>
+                    <pwm:display key="Button_Continue"/>
+                </button>
+                <input type="hidden" name="pwmFormID" id="pwmFormID" value="<pwm:FormID/>"/>
+            </form>
+            <form action="<pwm:current-url/>" method="post" enctype="application/x-www-form-urlencoded" style="display: inline;">
+                <input type="hidden" name="processAction" value="reset"/>
+                <button type="submit" name="button" class="btn" id="button_reset">
+                    <pwm:if test="<%=PwmIfTest.showIcons%>"><span class="btn-icon pwm-icon pwm-icon-backward"></span></pwm:if>
+                    <pwm:display key="Button_Cancel"/>
+                </button>
+                <input type="hidden" name="pwmFormID" value="<pwm:FormID/>"/>
+            </form>
+        </div>
+    </div>
+    <div class="push"></div>
+</div>
+<pwm:script>
+    <script type="text/javascript">
+        function updateContinueButton() {
+            var checkBox = PWM_MAIN.getObject("agreeCheckBox");
+            var continueButton = PWM_MAIN.getObject("submitBtn");
+            if (checkBox != null && continueButton != null) {
+                if (checkBox.checked) {
+                    continueButton.removeAttribute('disabled');
+                } else {
+                    continueButton.disabled = "disabled";
+                }
+            }
+        }
+        PWM_GLOBAL['startupFunctions'].push(function(){
+            PWM_MAIN.addEventHandler('agreeCheckBox','click, change',function(){ updateContinueButton() });
+            updateContinueButton();
+        });
+    </script>
+</pwm:script>
+<%@ include file="fragment/footer.jsp" %>
+</body>
+</html>