How can I enable (and require)
n-factor authentication for all SSH connections to a CentOS 7 server?
I have read about Google Authenticator, which provides two factor authentication. But that is limited to a pin provided by an app that you have to install in each user's mobile device.
How can I add variable numbers of authentication factors? Some examples of additional factors might include:
1.) a pin code emailed to the administrator's work email address
2.) a USB key
3.) a pin texted to the administrator using a tool like twilio
A Java program to send the pin emails and texts would be easy enough to build, and could be called by a shell script that replaces the default ssh authentication script, but I have never written a shell script before.
What would the shell code look like to accomplish this, assuming the Java is already written? And where would I place the shell script? The pseudo-code for the shell script might include the following steps:
1.) Trigger the Java program to send email, text, etc. with custom pins
when administrator types ssh [email protected]
2.) Replace the login password prompt with a series of prompts to
get the pins/credentials from
2.) Possibly interact with a client program to get the usb signature
3.) Send the credentials to the java program, with time stamp to ensure
login was done within a minute after java sent the pins
4.) Compare the Boolean returned by the java program with the CentOS password check
5.) Either authenticate or reject the user
My guess as to a first draft of a shell script might be:
USER_NAME=#How do I populate this?
TEXT_PIN=shuf -i 1-10000 -n 1
EMAIL_PIN=shuf -i 1-10000 -n 1
java -cp $CLASSPATH my.package.SendPinsClass TEXT_PIN EMAIL_PIN
if [ $? -eq 0 ]
echo -n "We were not able to send authentication credentials. Please log the current time and report this to the chief administrator. "
echo -n "Pin numbers have been sent to your email and phone number. Please check your email and text messages now before continuing the authentication process. "
echo -n "Enter Pin number from cell phone: "
echo -n "Enter Pin number from email: "
java -cp $CLASSPATH my.package.AuthenticationClass USER_NAME TEXT_PIN EMAIL_PIN
if [ $? -eq 0 ]
#DO NOT AUTHENTICATE
#LOG THIS USER IN!
#HOW DO WE CHECK THE USER'S CentOS 7 PASSWORD?
#THIS SCRIPT MUST INCLUDE A PASSWORD CHECK IN AUTHENTICATION PROCESS.
What else goes in the shell script? And how to I put it in place?
The specifications for an answer are given above. However, comments suggesting easier tools instead of rolling one's own are also welcome as comments.
Based on my ongoing research, I just added more explicit detail to the rough draft of the shell script above to document the steps that the script must take in order to authenticate the user. Key steps can be assumed to successfully be completed by two "black box" java programs that are called by the shell script. The major remaining questions that must be answered before this can be completed include:
1.) How does the script receive and populate the value for the USER_NAME variable?
2.) How does the script check the user's CentOS 7 OS password, and
how should the password be integrated into the script's authentication
process? Note the security of the password needs to be protected.
3.) How does the script process the approval or rejection of the
authentication request with the CentOS 7 operating system?
4.) How is the working shell script placed in the authentication
process to replace the default authentication script?
Note: If implementation of the script in CentOS 7 involves bundling the script as a
PAM module as @steve suggests in his comment, then the accepted answer needs to give explicit instructions not only for altering the shell script, but also for integrating the shell script into the
PAM module and any other aspects of the authentication process. The answer needs to work on CentOS 7.
Per this link which was posted in a comment by @steve below, the contents of
/etc/pam.d/sshd are by default as follows:
auth required pam_sepermit.so
auth substack password-auth
auth include postlogin
account required pam_nologin.so
account include password-auth
password include password-auth
# pam_selinux.so close should be the first session rule
session required pam_selinux.so close
session required pam_loginuid.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session required pam_selinux.so open env_params
session optional pam_keyinit.so force revoke
session include password-auth
session include postlogin
Note that, in CentOS 7,
/lib/security/ does not exist, and is thus not the location of PAM modules, as in @steve's link, which is for Debian. Thus, without the PAM modules, we cannot store the shell script in my OP as
/lib/security/2ndfactor.so. The tutorial in @steve's link suggests the following code to assign the script to
/lib/security/2ndfactor.so. How do we change the following code?
apt-get install build-essential libpam0g-dev libcurl4-openssl-dev
gcc -fPIC -lcurl -c 2ndfactor.c
ld -lcurl -x --shared -o /lib/security/2ndfactor.so 2ndfactor.o
@steve's link also suggests that we edit
/etc/pam.d/sshd to add a reference to the
@common-auth as follows:
# PAM configuration for the Secure Shell service
# Read environment variables from /etc/environment and
auth required pam_env.so # 
# In Debian 4.0 (etch), locale-related environment variables were moved to
# /etc/default/locale, so read that as well.
auth required pam_env.so envfile=/etc/default/locale
# Standard Un*x authentication.
auth required 2ndfactor.so base_url=http://my.server.com/send_code.php code_size=5
But, as you can see above, the
/etc/pam.d/sshd that comes default in CentOS 7 does not contain
@include common-auth. Also, @steve's link uses a web url for a php script, but I am trying to call a java program from a shell script. There must be a way to do this without exposing a web url.
Lastly, @steve's link says to set
ChallengeResponseAuthentication = yes in
/etc/ssd/sshd_config, but in CentOS 7 there is no
Can someone please show how to adapt all this to work with CentOS 7 and Java?