Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing the password when the flag "User must change password at next logon" is setted #414

Open
EuGras-itools opened this issue Aug 26, 2020 · 10 comments
Labels
feedback required Waiting for a feedback question

Comments

@EuGras-itools
Copy link

Hello,
I have a problem when trying to change the password of a AD user for which the flag "User must change password at next logon" is setted.
SSP frontend returns error "Password was refused by the LDAP directory".
According to the logs and to the comment from another issue (#216 (comment)) rebind under the manager account probably does not happen.
Option $who_change_password = "user"; is required for us because password group policies works only with it.
My environment: Windows server 2019 with configured LDAPS.

Part of SSP config:

$ldap_url = "ldaps://HIDDEN:636";
$ldap_binddn = "cn=manager,cn=HIDDEN,dc=HIDDEN,dc=HIDDEN";
$ldap_bindpw = "HIDDEN";
$ldap_base = "dc=HIDDEN,dc=HIDDEN";
$ldap_login_attribute = "sAMAccountName";
$who_change_password = "user";
$ad_mode = true;
$ad_options['change_expired_password'] = true;

Part of /var/log/apache2/error.log:

error.log
** ld 0x55ef5edb43c0 Connections:
* host:HIDDEN  port: 636  (default)
  refcnt: 2  status: Connected
  last used: Wed Aug 26 15:41:08 2020


** ld 0x55ef5edb43c0 Outstanding Requests:
 * msgid 3,  origid 3, status InProgress
   outstanding referrals 0, parent count 0
  ld 0x55ef5edb43c0 request count 1 (abandoned 0)
** ld 0x55ef5edb43c0 Response Queue:
   Empty
  ld 0x55ef5edb43c0 response count 0
ldap_chkResponseList ld 0x55ef5edb43c0 msgid 3 all 1
ldap_chkResponseList returns ld 0x55ef5edb43c0 NULL
ldap_int_select
read1msg: ld 0x55ef5edb43c0 msgid 3 all 1
read1msg: ld 0x55ef5edb43c0 msgid 3 message type bind
read1msg: ld 0x55ef5edb43c0 0 new referrals
read1msg:  mark request completed, ld 0x55ef5edb43c0 msgid 3
request done: ld 0x55ef5edb43c0 msgid 3
res_errno: 49, res_error: <80090308: LdapErr: DSID-0C09041C, comment: AcceptSecurityContext error, data 773, v4563>, res_matched: <>
ldap_free_request (origid 3, msgid 3)
ldap_parse_result
ldap_msgfree
ldap_err2string
ldap_err2string
ldap_err2string
ldap_modify_ext
ldap_send_initial_request
ldap_send_server_request
ldap_result ld 0x55ef5edb43c0 msgid 4
wait4msg ld 0x55ef5edb43c0 msgid 4 (infinite timeout)
wait4msg continue ld 0x55ef5edb43c0 msgid 4 all 1
** ld 0x55ef5edb43c0 Connections:
* host: HIDDEN  port: 636  (default)
  refcnt: 2  status: Connected
  last used: Wed Aug 26 15:41:08 2020


** ld 0x55ef5edb43c0 Outstanding Requests:
 * msgid 4,  origid 4, status InProgress
   outstanding referrals 0, parent count 0
  ld 0x55ef5edb43c0 request count 1 (abandoned 0)
** ld 0x55ef5edb43c0 Response Queue:
   Empty
  ld 0x55ef5edb43c0 response count 0
ldap_chkResponseList ld 0x55ef5edb43c0 msgid 4 all 1
ldap_chkResponseList returns ld 0x55ef5edb43c0 NULL
ldap_int_select
read1msg: ld 0x55ef5edb43c0 msgid 4 all 1
read1msg: ld 0x55ef5edb43c0 msgid 4 message type modify
read1msg: ld 0x55ef5edb43c0 0 new referrals
read1msg:  mark request completed, ld 0x55ef5edb43c0 msgid 4
request done: ld 0x55ef5edb43c0 msgid 4
res_errno: 1, res_error: <000004DC: LdapErr: DSID-0C090F45, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v4563>, res_matched: <>
ldap_free_request (origid 4, msgid 4)
ldap_parse_result
ldap_msgfree
ldap_err2string
ldap_err2string
ldap_msgfree
ldap_free_connection 1 1
ldap_send_unbind
ldap_free_connection: actually freed
Part of /var/log/apache2/ssp_error.log:
ssp_error.log
[Wed Aug 26 15:41:08.683323 2020] [php7:warn] [pid 15173] [client HIDDEN:54322] PHP Warning:  ldap_bind(): Unable to bind to server: Invalid credentials in /usr/share/self-service-password/pages/change.php on line 131, referer: https:/HIDDEN/index.php
[Wed Aug 26 15:41:08.683350 2020] [php7:notice] [pid 15173] [client HIDDEN:54322] LDAP - Bind user error 49  (Invalid credentials), referer: https://HIDDEN/index.php
[Wed Aug 26 15:41:08.683359 2020] [php7:notice] [pid 15173] [client HIDDEN:54322] LDAP - Bind user extended_error 80090308: LdapErr: DSID-0C09041C, comment: AcceptSecurityContext error, data 773, v4563  (Invalid credentials), referer: https:/HIDDEN/index.php
[Wed Aug 26 15:41:08.683364 2020] [php7:notice] [pid 15173] [client HIDDEN:54322] LDAP - Bind user password needs to be changed, referer: https://HIDDEN/index.php
[Wed Aug 26 15:41:08.684127 2020] [php7:warn] [pid 15173] [client HIDDEN:54322] PHP Warning:  ldap_modify_batch(): Batch Modify: Operations error in /usr/share/self-service-password/lib/functions.inc.php on line 396, referer: https://HIDDEN/index.php
[Wed Aug 26 15:41:08.684141 2020] [php7:notice] [pid 15173] [client HIDDEN:54322] LDAP - Modify password error 1 (Operations error), referer: https://HIDDEN/index.php
@coudot
Copy link
Member

coudot commented Aug 27, 2020

Hello,

our code is:

        if ( ($errno == 49) && $ad_mode ) {
            if ( ldap_get_option($ldap, 0x0032, $extended_error) ) {
                error_log("LDAP - Bind user extended_error $extended_error  (".ldap_error($ldap).")");
                $extended_error = explode(', ', $extended_error);
                if ( strpos($extended_error[2], '773') or strpos($extended_error[0], 'NT_STATUS_PASSWORD_MUST_CHANGE') ) {
                    error_log("LDAP - Bind user password needs to be changed");
                    $result = "";
                }
                if ( ( strpos($extended_error[2], '532') or strpos($extended_error[0], 'NT_STATUS_ACCOUNT_EXPIRED') ) and $ad_options['change_expired_password'] ) {
                    error_log("LDAP - Bind user password is expired");
                    $result = "";
                }
                unset($extended_error);
            }
        }
    }
    if ( $result === "" )  {

        # Rebind as Manager if needed
        if ( $who_change_password == "manager" ) {
            $bind = ldap_bind($ldap, $ldap_binddn, $ldap_bindpw);
        }

    }}}}}

Means we only rebind as manager if this is set in $who_change_password.

In your case, the $who_change_password is set to user, so we don't rebind, and then the modification is not accepted by AD. I don't see any obvious solution to this.

@EuGras-itools
Copy link
Author

Thanks for quick reply .If the "User must change password at next logon" flag is not set for the user, but the $who_change_password = "manager" option is set, the password will be changed through the
administrative reset by manager or through the change by user?

@coudot
Copy link
Member

coudot commented Aug 27, 2020

It will be changed through the manager account

@EuGras-itools
Copy link
Author

The problem was solved by modifying the php code of the change.php file from line # 138 and below:

        if ( ($errno == 49) && $ad_mode ) {
            if ( ldap_get_option($ldap, 0x0032, $extended_error) ) {
                error_log("LDAP - Bind user extended_error $extended_error  (".ldap_error($ldap).")");
                $extended_error = explode(', ', $extended_error);
                if ( strpos($extended_error[2], '773') or strpos($extended_error[0], 'NT_STATUS_PASSWORD_MUST_CHANGE') ) {
                    error_log("LDAP - Bind user password needs to be changed");
                    $result = "need_manager";
                }
                if ( ( strpos($extended_error[2], '532') or strpos($extended_error[0], 'NT_STATUS_ACCOUNT_EXPIRED') ) and $ad_options['change_expired_password'] ) {
                    error_log("LDAP - Bind user password is expired");
                    $result = "need_manager";
                }
                unset($extended_error);
            }
        }
    }
    if ( $result === "need_manager" )  {

        # Rebind as Manager if needed
        $who_change_password = "manager";
        $bind = ldap_bind($ldap, $ldap_binddn, $ldap_bindpw);
        $result = "";
    }}}}}

@coudot
Copy link
Member

coudot commented Aug 27, 2020

Were you also able to test an account with an expired password?

And what about the fact the group policy does not apply when password is changed by user? Is it ok for you to bypass AD policy if the user must reset its password?

@EuGras-itools
Copy link
Author

Yes this is a dirty hack. And when the flag "User must change password at next logon" is setted password group policy wouldn't apply when password changed, because the password is changed by the manager. But in other cases this should work.
These group policies are important to us:

@EuGras-itools
Copy link
Author

EuGras-itools commented Aug 27, 2020

not tested yet

Were you also able to test an account with an expired password?

@EuGras-itools
Copy link
Author

I modified the "change.php" file to make group policies work:

  • "Enforce password history"
  • "Minimum password age".

When changing the password, an intermediate step of setting a temporary password is used. This temporarily modifies the "UserAccountControl" and "pwdLastSet" attributes.

change.php
<?php
#==============================================================================
# LTB Self Service Password
#
# Copyright (C) 2009 Clement OUDOT
# Copyright (C) 2009 LTB-project.org
#
# 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.
#
# GPL License: http://www.gnu.org/licenses/gpl.txt
#
#==============================================================================

# This page is called to change password

#==============================================================================
# POST parameters
#==============================================================================
# Initiate vars
$result = "";
$login = "";
$confirmpassword = "";
$newpassword = "";
$oldpassword = "";
$ldap = "";
$userdn = "";
if (!isset($pwd_forbidden_chars)) { $pwd_forbidden_chars=""; }
$mail = "";
$tmp_password = "";
$flag = "";

if (isset($_POST["confirmpassword"]) and $_POST["confirmpassword"]) { $confirmpassword = strval($_POST["confirmpassword"]); }
 else { $result = "confirmpasswordrequired"; }
if (isset($_POST["newpassword"]) and $_POST["newpassword"]) { $newpassword = strval($_POST["newpassword"]); }
 else { $result = "newpasswordrequired"; }
if (isset($_POST["oldpassword"]) and $_POST["oldpassword"]) { $oldpassword = strval($_POST["oldpassword"]); }
 else { $result = "oldpasswordrequired"; }
if (isset($_REQUEST["login"]) and $_REQUEST["login"]) { $login = strval($_REQUEST["login"]); }
 else { $result = "loginrequired"; }
if (! isset($_REQUEST["login"]) and ! isset($_POST["confirmpassword"]) and ! isset($_POST["newpassword"]) and ! isset($_POST["oldpassword"]))
 { $result = "emptychangeform"; }

# Check the entered username for characters that our installation doesn't support
if ( $result === "" ) {
    $result = check_username_validity($login,$login_forbidden_chars);
}

# Match new and confirm password
if ( $newpassword != $confirmpassword ) { $result="nomatch"; }

#==============================================================================
# Check reCAPTCHA
#==============================================================================
if ( $result === "" && $use_recaptcha ) {
    $result = check_recaptcha($recaptcha_privatekey, $recaptcha_request_method, $_POST['g-recaptcha-response'], $login);
}

#==============================================================================
# Check old password
#==============================================================================
if ( $result === "" ) {

    # Connect to LDAP
    $ldap = ldap_connect($ldap_url);
    ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
    ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
    if ( $ldap_starttls && !ldap_start_tls($ldap) ) {
        $result = "ldaperror";
        error_log("LDAP - Unable to use StartTLS");
    } else {

    # Bind
    if ( isset($ldap_binddn) && isset($ldap_bindpw) ) {
        $bind = ldap_bind($ldap, $ldap_binddn, $ldap_bindpw);
    } else {
        $bind = ldap_bind($ldap);
    }

    if ( !$bind ) {
        $result = "ldaperror";
        $errno = ldap_errno($ldap);
        if ( $errno ) {
	    error_log("LDAP - Bind error $errno  (".ldap_error($ldap).")");
        }
    } else {

    # Search for user
    $ldap_filter = str_replace("{login}", $login, $ldap_filter);
    $search = ldap_search($ldap, $ldap_base, $ldap_filter);

    $errno = ldap_errno($ldap);
    if ( $errno ) {
        $result = "ldaperror";
        error_log("LDAP - Search error $errno  (".ldap_error($ldap).")");
    } else {

    # Get user DN
    $entry = ldap_first_entry($ldap, $search);
    $userdn = ldap_get_dn($ldap, $entry);

    if( !$userdn ) {
        $result = "badcredentials";
        error_log("LDAP - User $login not found");
    } else {

    # Get user email for notification
    if ( $notify_on_change ) {
        $mailValues = ldap_get_values($ldap, $entry, $mail_attribute);
        if ( $mailValues["count"] > 0 ) {
            $mail = $mailValues[0];
        }
    }
    # Get user UserAccountControl attribute value
    if ( $ad_mode ) {
        $uacValueArray = ldap_get_values($ldap, $entry, 'UserAccountControl');
        $uacValue = $uacValueArray[0];
    }

    # Check objectClass to allow samba and shadow updates
    $ocValues = ldap_get_values($ldap, $entry, 'objectClass');
    if ( !in_array( 'sambaSamAccount', $ocValues ) and !in_array( 'sambaSAMAccount', $ocValues ) ) {
        $samba_mode = false;
    }
    if ( !in_array( 'shadowAccount', $ocValues ) ) {
        $shadow_options['update_shadowLastChange'] = false;
        $shadow_options['update_shadowExpire'] = false;
    }

    # Bind with old password
    $bind = ldap_bind($ldap, $userdn, $oldpassword);
    if ( !$bind ) {
        $result = "badcredentials";
        $errno = ldap_errno($ldap);
        if ( $errno ) {
            error_log("LDAP - Bind user error $errno  (".ldap_error($ldap).")");
        }
        if ( ($errno == 49) && $ad_mode ) {
            if ( ldap_get_option($ldap, 0x0032, $extended_error) ) {
                error_log("LDAP - Bind user extended_error $extended_error  (".ldap_error($ldap).")");
                $extended_error = explode(', ', $extended_error);
                if ( strpos($extended_error[2], '773') or strpos($extended_error[0], 'NT_STATUS_PASSWORD_MUST_CHANGE') ) {
                    error_log("LDAP - Bind user password needs to be changed");
                    $flag = "need_manager";
                    $result = "";
                }
                if ( ( strpos($extended_error[2], '532') or strpos($extended_error[0], 'NT_STATUS_ACCOUNT_EXPIRED') ) and $ad_options['change_expired_password'] ) {
                    error_log("LDAP - Bind user password is expired");
                    $flag = "need_manager";
                    $result = "";
                }
                unset($extended_error);
            }
        }
    }

    # Rebind as Manager if needed, set the user password using a randomly generated temporary password
    if ( $flag === "need_manager" && $who_change_password === "user" )  {
        $tmp_password = base64_encode(random_bytes(10));
        $tmp_who_change_password = "manager";
        # Bind as manager
        $bind = ldap_bind($ldap, $ldap_binddn, $ldap_bindpw);
        # Check password strength
        $result = check_password_strength( $newpassword, $oldpassword, $pwd_policy_config, $login );
        # Set temp password for user and temporary set user's attributes for working of group policies next time setting new password
        if ( $result === "" ) {
            $result = change_password($ldap, $userdn, $tmp_password, $ad_mode, $ad_options, $samba_mode, $samba_options, $shadow_options, $hash, $hash_options, $tmp_who_change_password, $oldpassword);
            $userdata["UserAccountControl"] = 66048;
            $userdata["pwdLastSet"] = 0;
            $replace = ldap_mod_replace($ldap, $userdn, $userdata);
            $oldpassword2 = $oldpassword;
            $oldpassword = $tmp_password;
            $bind = ldap_bind($ldap, $userdn, $oldpassword);
            $result = "";
        }
    }}}}}

}

#==============================================================================
# Check password strength
#==============================================================================
if ( $result === "" ) {
    $result = check_password_strength( $newpassword, $oldpassword, $pwd_policy_config, $login );
}

#==============================================================================
# Change password
#==============================================================================
if ( $result === "" ) {
    $result = change_password($ldap, $userdn, $newpassword, $ad_mode, $ad_options, $samba_mode, $samba_options, $shadow_options, $hash, $hash_options, $who_change_password, $oldpassword);
    if ( $flag === "need_manager" && $who_change_password === "user" ) {
        $bind = ldap_bind($ldap, $ldap_binddn, $ldap_bindpw);
        $userdata["UserAccountControl"] = $uacValue;
        $userdata["pwdLastSet"] = -1;
        $replace = ldap_mod_replace($ldap, $userdn, $userdata);
    }
    
    if ( $result !== "passwordchanged") {
        if ( $flag === "need_manager" && $who_change_password === "user" ) {
            $bind = ldap_bind($ldap, $ldap_binddn, $ldap_bindpw);
            $result = change_password($ldap, $userdn, $oldpassword2, $ad_mode, $ad_options, $samba_mode, $samba_options, $shadow_options, $hash, $hash_options, $tmp_who_change_password, $oldpassword);
            $userdata["pwdLastSet"] = 0;
            $replace = ldap_mod_replace($ldap, $userdn, $userdata);
            $result = "passworderror";
        } else {
            $result = "passworderror";

        }
    }
    if ( $result === "passwordchanged" && isset($posthook) ) {
        $command = escapeshellcmd($posthook).' '.escapeshellarg($login).' '.escapeshellarg($newpassword).' '.escapeshellarg($oldpassword);
        exec($command, $posthook_output, $posthook_return);
    }
}

#==============================================================================
# HTML
#==============================================================================
if ( in_array($result, $obscure_failure_messages) ) { $result = "badcredentials"; }
?>

<div class="result alert alert-<?php echo get_criticity($result) ?>">
<p><i class="fa fa-fw <?php echo get_fa_class($result) ?>" aria-hidden="true"></i> <?php echo $messages[$result]; ?></p>
</div>

<?php if ( $display_posthook_error and $posthook_return > 0 ) { ?>

<div class="result alert alert-warning">
<p><i class="fa fa-fw fa-exclamation-triangle" aria-hidden="true"></i> <?php echo $posthook_output[0]; ?></p>
</div>

<?php } ?>

<?php if ( $result !== "passwordchanged" ) { ?>

<?php
if ( $show_help ) {
    echo "<div class=\"help alert alert-warning\"><p>";
    echo "<i class=\"fa fa-fw fa-info-circle\"></i> ";
    echo $messages["changehelp"];
    echo "</p>";
    if (isset($messages['changehelpextramessage'])) {
        echo "<p>" . $messages['changehelpextramessage'] . "</p>";
    }
    if ( !$show_menu and ( $use_questions or $use_tokens or $use_sms or $change_sshkey ) ) {
        echo "<p>".  $messages["changehelpreset"] . "</p>";
        echo "<ul>";
        if ( $use_questions ) {
            echo "<li>" . $messages["changehelpquestions"] ."</li>";
        }
        if ( $use_tokens ) {
            echo "<li>" . $messages["changehelptoken"] ."</li>";
        }
        if ( $use_sms ) {
            echo "<li>" . $messages["changehelpsms"] ."</li>";
        }
        if ( $change_sshkey ) {
            echo "<li>" . $messages["changehelpsshkey"] . "</li>";
        }
        echo "</ul>";
    }
    echo "</div>\n";
}
?>

<?php
if ($pwd_show_policy_pos === 'above') {
    show_policy($messages, $pwd_policy_config, $result);
}
?>

<div class="alert alert-info">
<form action="#" method="post" class="form-horizontal">
    <div class="form-group">
        <label for="login" class="col-sm-4 control-label"><?php echo $messages["login"]; ?></label>
        <div class="col-sm-8">
            <div class="input-group">
                <span class="input-group-addon"><i class="fa fa-fw fa-user"></i></span>
                <input type="text" name="login" id="login" value="<?php echo htmlentities($login) ?>" class="form-control" placeholder="<?php echo $messages["login"]; ?>" />
            </div>
        </div>
    </div>
    <div class="form-group">
        <label for="oldpassword" class="col-sm-4 control-label"><?php echo $messages["oldpassword"]; ?></label>
        <div class="col-sm-8">
            <div class="input-group">
                <span class="input-group-addon"><i class="fa fa-fw fa-lock"></i></span>
                <input type="password" name="oldpassword" id="oldpassword" class="form-control" placeholder="<?php echo $messages["oldpassword"]; ?>" />
            </div>
        </div>
    </div>
    <div class="form-group">
        <label for="newpassword" class="col-sm-4 control-label"><?php echo $messages["newpassword"]; ?></label>
        <div class="col-sm-8">
            <div class="input-group">
                <span class="input-group-addon"><i class="fa fa-fw fa-lock"></i></span>
                <input type="password" name="newpassword" id="newpassword" class="form-control" placeholder="<?php echo $messages["newpassword"]; ?>" />
            </div>
        </div>
    </div>
    <div class="form-group">
        <label for="confirmpassword" class="col-sm-4 control-label"><?php echo $messages["confirmpassword"]; ?></label>
        <div class="col-sm-8">
            <div class="input-group">
                <span class="input-group-addon"><i class="fa fa-fw fa-lock"></i></span>
                <input type="password" name="confirmpassword" id="confirmpassword" class="form-control" placeholder="<?php echo $messages["confirmpassword"]; ?>" />
            </div>
        </div>
    </div>
<?php if ($use_recaptcha) { ?>
    <div class="form-group">
        <div class="col-sm-offset-4 col-sm-8">
            <div class="g-recaptcha" data-sitekey="<?php echo $recaptcha_publickey; ?>" data-theme="<?php echo $recaptcha_theme; ?>" data-type="<?php echo $recaptcha_type; ?>" data-size="<?php echo $recaptcha_size; ?>"></div>
            <script type="text/javascript" src="https://www.google.com/recaptcha/api.js?hl=<?php echo $lang; ?>"></script>
        </div>
    </div>
<?php } ?>
    <div class="form-group">
        <div class="col-sm-offset-4 col-sm-8">
            <button type="submit" class="btn btn-success">
                <i class="fa fa-fw fa-check-square-o"></i> <?php echo $messages['submit']; ?>
            </button>
        </div>
    </div>
</form>
</div>

<?php
if ($pwd_show_policy_pos === 'below') {
    show_policy($messages, $pwd_policy_config, $result);
}
?>

<?php } else {

    # Notify password change
    if ($mail and $notify_on_change) {
        $data = array( "login" => $login, "mail" => $mail, "password" => $newpassword);
        if ( !send_mail($mailer, $mail, $mail_from, $mail_from_name, $messages["changesubject"], $messages["changemessage"].$mail_signature, $data) ) {
            error_log("Error while sending change email to $mail (user $login)");
        }
    }

    if (isset($messages['passwordchangedextramessage'])) {
        echo "<div class=\"result alert alert-" . get_criticity($result) . "\">";
        echo "<p><i class=\"fa fa-fw " . get_fa_class($result) . "\" aria-hidden=\"true\"></i> " . $messages['passwordchangedextramessage'] . "</p>";
        echo "</div>\n";
    }

}
?>


@andrich48
Copy link

I have the same problem.
I dont have an account with expired password for testing.
I have an account with valid password but with flag "need to change password on text logon".
I cannot use "manager" because its insecure :(
But I have a clue - "sambapasswd" utility from "samba 4" suite does that successfully.
It first tries to change the password, then after error 49 it tries to re-bind as anonymous and then does some magic and password is changed.
Unfortunately I dont fully understand their C++ code to do the same magic in PHP :(

@coudot
Copy link
Member

coudot commented Mar 22, 2021

There is a feature request to allow changing an expired password #96

Could you tell us what is working and not working with current code?

@coudot coudot added the feedback required Waiting for a feedback label Apr 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feedback required Waiting for a feedback question
Projects
None yet
Development

No branches or pull requests

3 participants