Add config file support, create users on the fly, update README

master
Skylar Ittner 6 years ago
parent e6d3c66d4a
commit de85cff905

@ -9,13 +9,28 @@ shell with root access open while experimenting.
Install the package libpam-python: Install the package libpam-python:
sudo apt-get install libpam-python sudo apt install libpam-python
Edit `pam_custom.py` and supply the Portal API URL and a valid API key. Edit `pam_netsyms.py` and supply the Portal API URL and a valid API key.
Copy the provided `pam_custom.py` to `/lib/security`: Copy the provided `pam_netsyms.py` to `/lib/security`:
sudo cp pam_custom.py /lib/security sudo cp pam_netsyms.py /lib/security
### Recommended Install
Make a file `/usr/share/pam-configs/netsyms` with the following content:
Name: Netsyms Business Apps authentication
Default: no
Priority: 256
Auth-Type: Primary
Auth:
[success=end default=ignore] pam_python.so pam_netsyms.py
Run `sudo pam-auth-update` and enable it
### Manual Install
Make a backup of the file `/etc/pam.d/common-auth`: Make a backup of the file `/etc/pam.d/common-auth`:
@ -25,7 +40,7 @@ Edit the file `/etc/pam.d/common-auth` introducing a line in which you
declare your custom authentication method. It should be something like declare your custom authentication method. It should be something like
this: this:
auth [success=2 default=ignore] pam_python.so pam_custom.py auth [success=2 default=ignore] pam_python.so pam_netsyms.py
and should be put just before (or after, according to your needs) the and should be put just before (or after, according to your needs) the
other authentication methods. other authentication methods.
@ -36,13 +51,14 @@ Some explanations:
2. "pam_python.so" is the name of the shared object that will be called by pam 2. "pam_python.so" is the name of the shared object that will be called by pam
3. "pam_custom.py" is the script in python that we provide 3. "pam_netsyms.py" is the script in python that we provide
### Sample /etc/pam.d/common-auth #### Sample /etc/pam.d/common-auth
This config file will gather the username and password and attempt a normal login. If that fails, PAM will try to process the login via this module. This config file will gather the username and password and attempt a normal login. If that fails, PAM will try to process the login via this module.
auth [success=2 default=ignore] pam_unix.so nullok_secure auth [success=2 default=ignore] pam_unix.so nullok_secure
auth [success=1 default=ignore] pam_python.so pam_custom.py auth [success=1 default=ignore] pam_python.so pam_netsyms.py
session required pam_mkhomedir.so skel=/etc/skel/ umask=0022
auth requisite pam_deny.so auth requisite pam_deny.so
auth required pam_permit.so auth required pam_permit.so

@ -3,7 +3,7 @@
''' '''
pam-custom pam-custom
Copyright (C) 2013 Loris Tisisno <loris.tissino@gmail.com> Copyright (C) 2013 Loris Tisisno <loris.tissino@gmail.com>
Copyright (C) 2017 Netsyms Technologies <admin@netsyms.com> Copyright (C) 2017-2018 Netsyms Technologies <contact@netsyms.com>
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -22,10 +22,25 @@
import os import os
import requests import requests
import json import json
import pwd
import crypt
import sys
api_url = "http://localhost/accounthub/api.php" api_url = "http:///accounthub/api.php"
api_key = "123" api_key = "123"
def load_settings():
global api_url
global api_key
if os.path.isfile("/etc/netsyms-business/config.json"):
with open("/etc/netsyms-business/config.json") as f:
text = f.read()
data = json.loads(text)
api_url = data['apiurl']
api_key = data['apikey']
def totp_verify(user, totp): def totp_verify(user, totp):
req = {"key": api_key, "action": "verifytotp", "username": user, "code": totp} req = {"key": api_key, "action": "verifytotp", "username": user, "code": totp}
resp = requests.post(api_url, data=req) resp = requests.post(api_url, data=req)
@ -39,7 +54,7 @@ def totp_check(user, pamh):
resp = requests.post(api_url, data=req) resp = requests.post(api_url, data=req)
if resp.json()['status'] == "OK": if resp.json()['status'] == "OK":
if resp.json()['otp'] == True: if resp.json()['otp'] == True:
otpmsg = pamh.Message(pamh.PAM_PROMPT_ECHO_ON, "[AccouhtHub] enter 2-factor auth code for " + user + ": ") otpmsg = pamh.Message(pamh.PAM_PROMPT_ECHO_ON, "Authentication code: ")
rsp = pamh.conversation(otpmsg) rsp = pamh.conversation(otpmsg)
otpcode = rsp.resp otpcode = rsp.resp
return totp_verify(user, otpcode) return totp_verify(user, otpcode)
@ -47,20 +62,32 @@ def totp_check(user, pamh):
return True return True
return False return False
def portal_auth(user, password, pamh):
def try_adduser(user, password):
try:
pwd.getpwnam(user)
except KeyError:
print('User ' + user + ' does not exist on this machine, creating...')
# stick this in if you want offline auth, but it isn't updated if the pwd changes in AccountHub
# -p $(mkpasswd -m sha-512 \"" + password + "\")
os.system("useradd -s "+ "/bin/bash "+ "-d "+ "/home/" + user + " -m " + user)
def accounthub_auth(user, password, pamh):
req = {"key": api_key, "action": "auth", "username": user, "password": password} req = {"key": api_key, "action": "auth", "username": user, "password": password}
resp = requests.post(api_url, data=req) resp = requests.post(api_url, data=req)
if resp.json()['status'] == "OK": if resp.json()['status'] == "OK":
return totp_check(user, pamh) if totp_check(user, pamh):
try_adduser(user, password)
return True
else:
return False
else: else:
return False return False
def pam_sm_authenticate(pamh, flags, argv): def pam_sm_authenticate(pamh, flags, argv):
load_settings()
# the basic idea for getting the password via pam.conversation comes from
# http://benctechnicalblog.blogspot.it/2011/05/pam-python-module-for-out-of-band.html
try: try:
user = pamh.get_user(None) user = pamh.get_user(None)
if user == None: if user == None:
@ -69,13 +96,13 @@ def pam_sm_authenticate(pamh, flags, argv):
password = pamh.authtok password = pamh.authtok
if password == None: if password == None:
## got no password in authtok - trying through conversation... ## got no password in authtok - trying through conversation...
passmsg = pamh.Message(pamh.PAM_PROMPT_ECHO_OFF, "[AccountHub] enter password for " + user + ": ") passmsg = pamh.Message(pamh.PAM_PROMPT_ECHO_OFF, "Password for " + user + ": ")
rsp = pamh.conversation(passmsg) rsp = pamh.conversation(passmsg)
password = rsp.resp password = rsp.resp
# so we should at this point have the password either through the # so we should at this point have the password either through the
# prompt or from previous module # prompt or from previous module
if portal_auth(user, password, pamh): if accounthub_auth(user, password, pamh):
return pamh.PAM_SUCCESS return pamh.PAM_SUCCESS
else: else:
return pamh.PAM_AUTH_ERR return pamh.PAM_AUTH_ERR
Loading…
Cancel
Save