Added feature #10017: [felogin] New Method for "forgotPassword"
authorSteffen Kamper <info@sk-typo3.de>
Thu, 3 Sep 2009 22:45:07 +0000 (22:45 +0000)
committerSteffen Kamper <info@sk-typo3.de>
Thu, 3 Sep 2009 22:45:07 +0000 (22:45 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@5891 709f56b5-9817-0410-a4d7-c38de5d9e867

ChangeLog
typo3/sysext/felogin/ext_emconf.php
typo3/sysext/felogin/ext_tables.php
typo3/sysext/felogin/ext_tables.sql
typo3/sysext/felogin/ext_typoscript_setup.txt
typo3/sysext/felogin/pi1/class.tx_felogin_pi1.php
typo3/sysext/felogin/pi1/locallang.xml
typo3/sysext/felogin/template.html

index a9417f6..3423b5b 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2009-09-04  Steffen Kamper  <info@sk-typo3.de>
+
+       * Added feature #10017: [felogin] New Method for "forgotPassword"
+
 2009-09-03  Martin Kutschker  <masi@typo3.org>
 
        * Added feature #11866: Greek transliteration
index 6be36b5..8dcd748 100644 (file)
@@ -29,7 +29,7 @@ $EM_CONF[$_EXTKEY] = array(
        'clearCacheOnLoad' => 1,
        'lockType' => '',
        'author_company' => '',
-       'version' => '1.1.0',
+       'version' => '1.2.0',
        'constraints' => array(
                'depends' => array(
                        'php' => '5.1.0-0.0.0',
index bd7b4a7..d3dcb0e 100644 (file)
@@ -17,11 +17,11 @@ $TCA['tt_content']['types']['login']['showitem']='CType;;4;;1-1-1, hidden, heade
                                                        --div--;LLL:EXT:cms/locallang_tca.xml:pages.tabs.access, starttime, endtime';
 
        // Adds the redirect-field to the fe_group- and fe_users-table
-$tempColumns = Array (
-       "felogin_redirectPid" => Array (
+$tempColumns = array (
+       "felogin_redirectPid" => array (
                "exclude" => 1,
                "label" => "LLL:EXT:felogin/locallang_db.xml:felogin_redirectPid",
-               "config" => Array (
+               "config" => array (
                        "type" => "group",
                        "internal_type" => "db",
                        "allowed" => "pages",
@@ -30,6 +30,13 @@ $tempColumns = Array (
                        "maxitems" => 1,
                )
        ),
+       'felogin_forgotHash' => array (
+               'exclude' => 1,
+               'label' => 'LLL:EXT:felogin/locallang_db.xml:felogin_forgotHash',
+               'config' => array (
+                       'type' => 'passthrough',
+               )
+       ),
 );
 
 t3lib_div::loadTCA("fe_groups");
index cd72cb4..60ef2f2 100644 (file)
@@ -11,7 +11,8 @@ CREATE TABLE fe_groups (
 # Table structure for table 'fe_users'
 #
 CREATE TABLE fe_users (
-       felogin_redirectPid  tinytext 
+       felogin_redirectPid  tinytext,
+       felogin_forgotHash  varchar(80) default '' 
 );
 
 
index a3f2324..cbc7979 100644 (file)
@@ -6,6 +6,9 @@ plugin.tx_felogin_pi1 {
                #Template File
        templateFile = EXT:felogin/template.html
        
+               #baseURL for the link generation
+       feloginBaseURL = 
+       
                #wrapContentInBaseClass
        wrapContentInBaseClass = 1
        
@@ -24,7 +27,11 @@ plugin.tx_felogin_pi1 {
        showForgotPasswordLink =
        showPermaLogin =
        
+               # time in hours how long the link for forget password is valid
+       forgotLinkHashValidTime = 12
        
+       newPasswordMinLength = 6
+
        welcomeHeader_stdWrap {
                wrap = <h3>|</h3>
        }
@@ -60,6 +67,14 @@ plugin.tx_felogin_pi1 {
                wrap = <div>|</div>
        }
        
+       changePasswordHeader_stdWrap {
+               wrap = <h3>|</h3>
+       }
+       changePasswordMessage_stdWrap {
+               wrap = <div>|</div>
+       }
+       
+       
        # stdWrap for fe_users fields used in Messages
        userfields {
                username {
@@ -86,7 +101,7 @@ plugin.tx_felogin_pi1 {
        # Allowed Referrer-Redirect-Domains:
        domains =
        
-       
+       dateFormat = Y-m-d H:i
 }
 
 plugin.tx_felogin_pi1._CSS_DEFAULT_STYLE (
index 2b23bb8..327405e 100644 (file)
@@ -108,6 +108,8 @@ class tx_felogin_pi1 extends tslib_pibase {
                $content='';
                if ($this->piVars['forgot']) {
                        $content .= $this->showForgot();
+               } elseif ($this->piVars['forgothash']) {  
+                       $content .= $this->changePassword();
                } else {
                        if($this->userIsLoggedIn && !$this->logintype) {
                                $content .= $this->showLogout();
@@ -139,65 +141,230 @@ class tx_felogin_pi1 extends tslib_pibase {
         protected function showForgot() {
                $subpart = $this->cObj->getSubpart($this->template, '###TEMPLATE_FORGOT###');
                $subpartArray = $linkpartArray = array();
+               $postData =  t3lib_div::_POST($this->prefixId);
 
-               if ($this->piVars['forgot_email']) {
-                       if (t3lib_div::validEmail($this->piVars['forgot_email'])) {
-                                       // look for user record and send the password
+               if ($postData['forgot_email']) {
+
+                               // get hashes for compare
+                       $postedHash = $postData['forgot_hash'];
+                       $hashData = $GLOBALS['TSFE']->fe_user->getKey('ses', 'forgot_hash');
+
+
+                       if ($postedHash === $hashData['forgot_hash']) {
+                               $row = FALSE;
+
+                                       // look for user record
+                               $data = $GLOBALS['TYPO3_DB']->fullQuoteStr($this->piVars['forgot_email'], 'fe_users');
                                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
-                                       'uid, username, password',
+                                       'uid, username, password, email',
                                        'fe_users',
-                                       'email='.$GLOBALS['TYPO3_DB']->fullQuoteStr($this->piVars['forgot_email'], 'fe_users').' AND pid IN ('.$GLOBALS['TYPO3_DB']->cleanIntList($this->spid).') '.$this->cObj->enableFields('fe_users')
+                                       '(email=' . $data .' OR username=' . $data . ') AND pid IN ('.$GLOBALS['TYPO3_DB']->cleanIntList($this->spid).') '.$this->cObj->enableFields('fe_users')
                                );
 
                                if ($GLOBALS['TYPO3_DB']->sql_num_rows($res)) {
                                        $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
-                                       $msg = sprintf($this->pi_getLL('ll_forgot_email_password', '', 0), $this->piVars['forgot_email'], $row['username'], $row['password']);
-                               } else {
-                                       $msg = sprintf($this->pi_getLL('ll_forgot_email_nopassword', '', 0), $this->piVars['forgot_email']);
                                }
 
-
-                                       // Generate new password with md5 and save it in user record
-                               if ($GLOBALS['TYPO3_DB']->sql_num_rows($res) && t3lib_extMgm::isLoaded('kb_md5fepw')) {
-                                       $newPass = $this->generatePassword(8);
-                                       $res = $GLOBALS['TYPO3_DB']->exec_UPDATEquery(
-                                               'fe_users',
-                                               'uid=' . $row['uid'],
-                                               array('password' => md5($newPass))
-                                       );
-                                       $msg = sprintf($this->pi_getLL('ll_forgot_email_password', '', 0),$this->piVars['forgot_email'], $row['username'], $newPass);
+                               if ($row) {
+                                                       // generate an email with the hashed link
+                                               $error = $this->generateAndSendHash($row);
+                               }
+                                       // generate message
+                               if ($error) {
+                                       $markerArray['###STATUS_MESSAGE###'] = $this->cObj->stdWrap($error, $this->conf['forgotMessage_stdWrap.']);     
+                               } else {
+                                       $markerArray['###STATUS_MESSAGE###'] = $this->cObj->stdWrap($this->pi_getLL('ll_forgot_reset_message_emailSent', '', 1), $this->conf['forgotMessage_stdWrap.']);
                                }
-
-                               $this->cObj->sendNotifyEmail($msg, $this->piVars['forgot_email'], '', $this->conf['email_from'], $this->conf['email_fromName'], $this->conf['replyTo']);
-                               $markerArray['###STATUS_MESSAGE###'] = $this->cObj->stdWrap(sprintf($this->pi_getLL('ll_forgot_message_emailSent', '', 1), '<em>' . htmlspecialchars($this->piVars['forgot_email']) .'</em>'), $this->conf['forgotMessage_stdWrap.']);
                                $subpartArray['###FORGOT_FORM###'] = '';
 
 
                        } else {
                                        //wrong email
-                               $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('forgot_message', $this->conf['forgotMessage_stdWrap.']);
+                               $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('forgot_reset_message', $this->conf['forgotMessage_stdWrap.']);
                                $markerArray['###BACKLINK_LOGIN###'] = '';
                        }
                } else {
-                       $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('forgot_message', $this->conf['forgotMessage_stdWrap.']);
+                       $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('forgot_reset_message', $this->conf['forgotMessage_stdWrap.']);
                        $markerArray['###BACKLINK_LOGIN###'] = '';
                }
 
                $markerArray['###BACKLINK_LOGIN###'] = $this->getPageLink($this->pi_getLL('ll_forgot_header_backToLogin', '', 1), array());
                $markerArray['###STATUS_HEADER###'] = $this->getDisplayText('forgot_header', $this->conf['forgotHeader_stdWrap.']);
 
-               $markerArray['###LEGEND###'] = $this->pi_getLL('send_password', '', 1);
+               $markerArray['###LEGEND###'] = $this->pi_getLL('reset_password', '', 1);
                $markerArray['###ACTION_URI###'] = $this->getPageLink('', array($this->prefixId . '[forgot]'=>1), true);
                $markerArray['###EMAIL_LABEL###'] = $this->pi_getLL('your_email', '', 1);
                $markerArray['###FORGOT_PASSWORD_ENTEREMAIL###'] = $this->pi_getLL('forgot_password_enterEmail', '', 1);
                $markerArray['###FORGOT_EMAIL###'] = $this->prefixId.'[forgot_email]';
-               $markerArray['###SEND_PASSWORD###'] = $this->pi_getLL('send_password', '', 1);
+               $markerArray['###SEND_PASSWORD###'] = $this->pi_getLL('reset_password', '', 1);
+
+               $markerArray['###DATA_LABEL###'] = $this->pi_getLL('ll_enter_your_data', '', 1);
+
+
+
                $markerArray = array_merge($markerArray, $this->getUserFieldMarkers());
 
+                       // generate hash
+               $hash = md5($this->generatePassword(3));
+               $markerArray['###FORGOTHASH###'] = $hash;
+                       // set hash in feuser session
+               $GLOBALS['TSFE']->fe_user->setKey('ses', 'forgot_hash', array('forgot_hash' => $hash));
+
+
                return $this->cObj->substituteMarkerArrayCached($subpart, $markerArray, $subpartArray, $linkpartArray);
        }
 
        /**
+        * This function checks the hash from link and checks the validity. If it's valid it shows the form for
+        * changing the password and process the change of password after submit, if not valid it returns the error message
+        *
+        * @return      string          The content.
+        */
+       protected function changePassword() {
+               
+               $subpartArray = $linkpartArray = array();
+               $done = false;  
+               
+               $minLength = intval($this->conf['newPasswordMinLength']) ? intval($this->conf['newPasswordMinLength']) : 6;
+               
+               $subpart = $this->cObj->getSubpart($this->template, '###TEMPLATE_CHANGEPASSWORD###');
+               
+               $markerArray['###STATUS_HEADER###'] = $this->getDisplayText('change_password_header', $this->conf['changePasswordHeader_stdWrap.']);    
+               $markerArray['###STATUS_MESSAGE###'] = sprintf($this->getDisplayText('change_password_message', $this->conf['changePasswordMessage_stdWrap.']), $minLength);    
+               
+               $markerArray['###BACKLINK_LOGIN###'] = '';
+               $uid = $this->piVars['user'];
+               $piHash = $this->piVars['forgothash'];
+               
+               $hash = explode('|', $piHash);
+               if (intval($uid) == 0) {
+                       $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('change_password_notvalid_message', $this->conf['changePasswordMessage_stdWrap.']);
+                       $subpartArray['###CHANGEPASSWORD_FORM###'] = '';                
+               } else {
+                       $user = $this->pi_getRecord('fe_users', intval($uid));
+                       $userHash = $user['felogin_forgotHash'];
+                       $compareHash = explode('|', $userHash);
+                       
+                       if (!$compareHash || !$compareHash[1] || $compareHash[0] < time() ||  $hash[0] != $compareHash[0] ||  md5($hash[1]) != $compareHash[1]) {
+                               $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('change_password_notvalid_message',$this->conf['changePasswordMessage_stdWrap.']);
+                               $subpartArray['###CHANGEPASSWORD_FORM###'] = '';         
+                       } else {
+                                       // all is fine, continue with new password
+                               $postData = t3lib_div::_POST($this->prefixId);
+
+                               if ($postData['changepasswordsubmit']) {
+                                       if (strlen($postData['password1']) < $minLength) {
+                                               $markerArray['###STATUS_MESSAGE###'] = sprintf($this->getDisplayText('change_password_tooshort_message', $this->conf['changePasswordMessage_stdWrap.']), $minLength); 
+                                       } elseif ($postData['password1'] != $postData['password2']) {
+                                               $markerArray['###STATUS_MESSAGE###'] = sprintf($this->getDisplayText('change_password_notequal_message', $this->conf['changePasswordMessage_stdWrap.']), $minLength);  
+                                       } else {
+                                               $newPass = $postData['password1']; 
+
+                                               if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['password_changed']) {
+                                                       $_params = array(
+                                                               'user' => $user,
+                                                               'newPassword' => $newPass,
+                                                       );
+                                                       foreach($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['password_changed'] as $_funcRef) {
+                                                               if ($_funcRef) {
+                                                                       t3lib_div::callUserFunction($_funcRef, $_params, $this);
+                                                               }
+                                                       }
+                                                       $newPass = $_params['newPassword'];
+                                               } 
+                                                       
+                                                       // save new password and clear DB-hash
+                                               $res = $GLOBALS['TYPO3_DB']->exec_UPDATEquery(
+                                                               'fe_users',
+                                                               'uid=' . $user['uid'],
+                                                               array('password' => $newPass, 'felogin_forgotHash' => '')
+                                                       );
+                                               $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('change_password_done_message', $this->conf['changePasswordMessage_stdWrap.']); 
+                                               $done = true;
+                                               $subpartArray['###CHANGEPASSWORD_FORM###'] = '';
+                                               $markerArray['###BACKLINK_LOGIN###'] = $this->getPageLink($this->pi_getLL('ll_forgot_header_backToLogin', '', 1), array()); 
+                                       }
+                               } 
+
+                               if (!$done) {
+                                       // Change password form
+                                       $markerArray['###ACTION_URI###'] = $this->pi_getPageLink($GLOBALS['TSFE']->id, '', array(
+                                               $this->prefixId . '[user]' => $user['uid'],
+                                               $this->prefixId . '[forgothash]' => $piHash
+                                       ));
+                                       $markerArray['###LEGEND###'] = $this->pi_getLL('change_password', '', 1);
+                                       $markerArray['###NEWPASSWORD1_LABEL###'] = $this->pi_getLL('newpassword_label1', '', 1);
+                                       $markerArray['###NEWPASSWORD2_LABEL###'] = $this->pi_getLL('newpassword_label2', '', 1);
+                                       $markerArray['###NEWPASSWORD1###'] = $this->prefixId . '[password1]';
+                                       $markerArray['###NEWPASSWORD2###'] = $this->prefixId . '[password2]';
+                                       $markerArray['###STORAGE_PID###'] = $this->spid;
+                                       $markerArray['###SEND_PASSWORD###'] = $this->pi_getLL('change_password', '', 1);
+                                       $markerArray['###FORGOTHASH###'] = $piHash;
+                               }                       
+                       }
+               }
+               
+               return $this->cObj->substituteMarkerArrayCached($subpart, $markerArray, $subpartArray, $linkpartArray);  
+       }
+       
+       /**
+        * generates a hashed link and send it with email
+        *
+        * @param       array           $user   contains user data
+        * @return      string          Empty string with success, error message with no success
+        */
+       protected function generateAndSendHash($user) {
+               $hours = intval($this->conf['forgotLinkHashValidTime']) > 0 ? intval($this->conf['forgotLinkHashValidTime']) : 24;
+               $validEnd = time() + 3600 * $hours;             
+               $validEndString = date($this->conf['dateFormat'], $validEnd);
+
+               $hash =  md5(rand());
+               $randHash = $validEnd . '|' . $hash;
+               $randHashDB = $validEnd . '|' . md5($hash);
+
+               //write hash to DB
+               $res = $GLOBALS['TYPO3_DB']->exec_UPDATEquery('fe_users', 'uid=' . $user['uid'], array('felogin_forgotHash' => $randHashDB));
+
+               // send hashlink to user
+               $this->conf['linkPrefix'] = -1;
+               $isAbsRelPrefix = !empty($GLOBALS['TSFE']->absRefPrefix);
+               $isBaseURL  = !empty($GLOBALS['TSFE']->baseUrl);
+               $isFeloginBaseURL = !empty($this->conf['feloginBaseURL']);
+
+               if ($isFeloginBaseURL) {
+                               // first priority
+                       $this->conf['linkPrefix'] = $this->conf['feloginBaseURL'];
+               } else {
+                       if ($isBaseURL) {
+                                       // 3rd priority
+                               $this->conf['linkPrefix'] = $GLOBALS['TSFE']->baseUrl;
+                       }
+               }
+
+               if ($this->conf['linkPrefix'] == -1 && !$isAbsRelPrefix) {              
+                               // no preix is set, return the error
+                       return $this->pi_getLL('ll_change_password_nolinkprefix_message');
+               }
+               
+               $link = ($isAbsRelPrefix ? '' : $this->conf['linkPrefix']) . $this->pi_getPageLink($GLOBALS['TSFE']->id, '', array(
+                       $this->prefixId . '[user]' => $user['uid'],
+                       $this->prefixId . '[forgothash]' => $randHash
+               ));
+
+               $msg = sprintf($this->pi_getLL('ll_forgot_validate_reset_password', '', 0), $user['username'], $link, $validEndString);
+
+                       // no RDCT - Links for security reasons
+               $oldSetting = $GLOBALS['TSFE']->config['config']['notification_email_urlmode'];
+               $GLOBALS['TSFE']->config['config']['notification_email_urlmode'] = 0;
+                       // send the email
+               $this->cObj->sendNotifyEmail($msg, $user['email'], '', $this->conf['email_from'], $this->conf['email_fromName'], $this->conf['replyTo']);
+                       // restore settings
+               $GLOBALS['TSFE']->config['config']['notification_email_urlmode'] = $oldSetting;  
+
+               return '';              
+       }
+
+       /**
         * Shows logout form
         *
         * @return      string          The content.
index e4b6d46..50cc3ce 100644 (file)
                        <label index="ll_error_header">Login failure</label>
                        <label index="ll_error_message">An error occurred during login. Most likely you didn't enter the username or password correctly.
 Be certain that you enter them precisely as they are, including upper/lower case.
-Another possibility is that cookies might be disabled in your webbrowser.</label>
+Another possibility is that cookies might be disabled in your web browser.</label>
                        <label index="ll_success_header">Login successful</label>
                        <label index="ll_success_message">You are now logged in as '###USER###'</label>
                        <label index="ll_status_header">Current status</label>
                        <label index="ll_status_message">This is your current status:</label>
-                       <label index="cookie_warning">Warning: There is a possibility that cookies are not enabled in your webbrowser! If your login disappears on your next click that is the case and you should enable cookies (or accept cookies from this website) immediately!</label>
+                       <label index="cookie_warning">Warning: There is a possibility that cookies are not enabled in your web browser! If your login disappears on your next click that is the case and you should enable cookies (or accept cookies from this website) immediately!</label>
                        <label index="username">Username:</label>
                        <label index="password">Password:</label>
                        <label index="login">Login</label>
                        <label index="permalogin">Stay logged in:</label>
                        <label index="logout">Logout</label>
                        <label index="send_password">Send password</label>
+                       <label index="reset_password">Reset Password</label>
+                       <label index="ll_change_password_header">Change your password</label>
+                       <label index="ll_change_password_message">Please enter your new password twice. Password needs a minimum length of %s chars.</label>
+                       <label index="ll_change_password_nolinkprefix_message">Error: there is no prefix for the link. Please set one of the following in your typoscript template: plugin.tx_felogin_pi1.feloginBaseURL = http://yourdomain/, config.baseURL = http://yourdomain/, config.absRelPrefix = http://yourdomain/</label>
+                       <label index="ll_change_password_notvalid_message">The link you clicked is not valid. Please repeat the forgot message procedure.</label>
+                       <label index="ll_change_password_notequal_message">The passwords are not equal, please enter your new password twice. Password needs a minimum length of %s chars.</label>
+                       <label index="ll_change_password_tooshort_message">The password length is too short. Please enter your new password twice. Password needs a minimum length of %s chars.</label>
+                       <label index="ll_change_password_done_message">Your password has been saved. You can now login with your new password.</label>
+                       <label index="change_password">Change your password</label>
+                       <label index="newpassword_label1">Enter new password</label>
+                       <label index="newpassword_label2">Repeat new password</label>
                        <label index="your_email">Your email:</label>
                        <label index="ll_forgot_header">Forgot your password?</label>
                        <label index="ll_forgot_email_password">Your password
@@ -41,9 +52,20 @@ Hi %s
 
 We couldn't find a username for this email address and so cannot send the password to you. Probably you misspelled the email address (upper/lower case makes a difference) or maybe you even didn't register yet?
                        </label>
+                       <label index="ll_forgot_validate_reset_password">Your new password
+Dear %s,
+
+This email was sent in response to your request to reset your password. Please click on the link below. 
+%s
+
+For security reasons, this link is only active until 2009-09-01 02:55. If you do not visit the link before then, you will need to repeat the password reset steps.
+                       </label>
                        <label index="ll_forgot_message">Please enter the email address by which you registered your user account. Then press &quot;Send password&quot; and your password will immediately be emailed to you. Make sure to spell your email address correctly.</label>
                        <label index="ll_forgot_message_emailSent">Your password has now been sent to the email address %s</label>
+                       <label index="ll_forgot_reset_message">Please enter your username or email address. Instructions for reseting the password will be immediately emailed to you.</label>
+                       <label index="ll_forgot_reset_message_emailSent">An email has been sent to the address stored in your account and contains a link to reset your password. If you do not receive an email, your account or email address was not found.</label>
                        <label index="ll_forgot_header_backToLogin">Return to login form</label>
+                       <label index="ll_enter_your_data">Username or email address:</label>
                </languageKey>
        </data>
 </T3locallang>
index 5021935..c4a00b7 100644 (file)
 
 <!-- ###FORGOT_FORM### -->
 <form action="###ACTION_URI###" method="post">
+    <div class="felogin-hidden">
+               <input type="hidden" name="tx_felogin_pi1[forgot_hash]" value="###FORGOTHASH###" />
+       </div>
        <fieldset>
        <legend>###LEGEND###</legend>
        <div>
-               <label for="###FORGOT_EMAIL###">###EMAIL_LABEL###</label>
+               <label for="###FORGOT_EMAIL###">###DATA_LABEL###</label>
                <input type="text" name="###FORGOT_EMAIL###" id="###FORGOT_EMAIL###" />
        </div>
        <div>
 
 
 
+<!--###TEMPLATE_CHANGEPASSWORD###-->
+
+###STATUS_HEADER###
+###STATUS_MESSAGE###
+
 
+<!-- ###CHANGEPASSWORD_FORM### -->
+<form action="###ACTION_URI###" method="post">
+       <fieldset>
+               <legend>###LEGEND###</legend>
+               <div>
+                       <label for="###NEWPASSWORD1###">###NEWPASSWORD1_LABEL###</label>
+                       <input type="password" name="###NEWPASSWORD1###" id="###NEWPASSWORD1###" />
+               </div>
+               <div>
+                       <label for="###NEWPASSWORD2###">###NEWPASSWORD2_LABEL###</label>
+                       <input type="password" name="###NEWPASSWORD2###" id="###NEWPASSWORD2###" />
+               </div>
+               <div>
+                       <input type="submit" name="tx_felogin_pi1[changepasswordsubmit]" value="###SEND_PASSWORD###" />
+                </div>
+       </fieldset>
+
+</form>
+<!-- ###CHANGEPASSWORD_FORM### -->
+###BACKLINK_LOGIN###
+<!--###TEMPLATE_CHANGEPASSWORD###-->