How to prevent a user from login in, but allow "su - user" in Linux?

Solution 1:

You can use AllowUsers / AllowGroups if you have only a few users/groups that are allowed to login via ssh or DenyUsers / DenyGroups if you have only a few users/groups that are not allowed to login. Note that this only restricts login via ssh, other ways of login (console, ftp, ...) are still possible. You need to add these options to your /etc/ssh/sshd_config file for most ssh installations.

If you have set the login shell to /bin/false you can use su -s /bin/bash user (replace /bin/bash with the shell of your choice)

Solution 2:

If you still want su to work, you can use sudo -u [username] or pass -s /bin/bash to su as a temporary shell. They both do the same in absence of a shell in /etc/passwd.

Solution 3:

If an account has no password (passwd -d username), they can't log in interactively (console, SSH, etc.). If they have a valid shell, su will still work. Note the "interactively," though; if somebody decides to set up an SSH keypair for the account, it will work!

Solution 4:

In sshd_config add a line DenyUser [username]

Note that this will not prevent that user from logging in via the console.

Solution 5:

In addition to what's been mentioned above (disable and/or not setting the user password), pam_access module (look up man page on pam_access and access.conf) can be used to control login access.