Skip to content

Password Self-Service

On the login node.

SLURM users can't use the standard passwd command, since their accounts exist only in LDAP, not the local system password database. spasswd is a custom self-service tool that lets slurm_-prefixed accounts update their own LDAP password securely — it uses ldappasswd with current-password verification and a confirmation prompt.

Not yet in Scripts/

Every other admin tool in this guide lives in User Management/Scripts/ and is linked from its doc page. spasswd is the one exception — it currently only exists as the inline script below. Recommend moving it into Scripts/spasswd for consistency (an inline ~85-line script in a markdown page is exactly the kind of content that silently drifts from what's actually deployed). This is a repo change beyond a docs edit — happy to do it as a quick follow-up if you'd like.

Path: /usr/local/bin/spasswd

sudo nano /usr/local/bin/spasswd
#!/usr/bin/env python3
import getpass
import sys
import os

def main():
    # Get the actual username (not the stripped version)
    actual_username = os.getenv('USER', '')

    # Check if username starts with slurm_
    if not actual_username.startswith('slurm_'):
        print("Error: This tool is only available for SLURM users (slurm_ accounts)")
        print(f"Your username '{actual_username}' is not authorized to use this tool")
        sys.exit(1)

    # Remove slurm_ prefix for LDAP operations
    ldap_username = actual_username.replace('slurm_', '', 1)

    print("=== SLURM Password Change ===")
    print(f"Changing password for: {ldap_username}")
    print()

    try:
        # Get passwords with custom prompts
        new_pass = getpass.getpass("Enter new password: ")
        confirm_pass = getpass.getpass("Confirm new password: ")

        if new_pass != confirm_pass:
            print("✗ Passwords don't match!")
            sys.exit(1)

        current_pass = getpass.getpass("Enter current password: ")

        # Build ldappasswd command
        import subprocess
        import shlex

        # Build the ldappasswd command with proper escaping
        ldap_cmd = [
            'ldappasswd',
            '-x',
            '-D', f'cn={ldap_username},ou=People,dc=jrcai,dc=lan',
            '-w', current_pass,
            '-s', new_pass,
            '-H', 'ldap://server02.jrcai.lan',
            '-ZZ'
        ]

        # Join the command with proper shell escaping
        ldap_cmd_str = ' '.join(shlex.quote(arg) for arg in ldap_cmd)

        # Properly initialize conda and deactivate before running ldappasswd
        full_cmd = f'''
        if [ -n "$CONDA_EXE" ]; then
            eval "$($CONDA_EXE shell.bash hook 2>/dev/null)" || true
            conda deactivate 2>/dev/null || true
        fi
        {ldap_cmd_str}
        '''

        # Execute command
        result = subprocess.run(['bash', '-c', full_cmd], capture_output=True, text=True)
        if result.returncode == 0:
            print("✓ Password changed successfully!")
        else:
            print("✗ Password change failed!")
            print(f"  Return code: {result.returncode}")
            print(f"  STDERR: {result.stderr}")
            if "Invalid credentials" in result.stderr:
                print("  Please check your current password.")

    except KeyboardInterrupt:
        print("\nOperation cancelled.")
        sys.exit(1)
    except Exception as e:
        print(f"✗ Error: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()

Allow execution:

sudo chmod +x /usr/local/bin/spasswd