A simple PAM authentication module for authenticating Linux users against the AccountHub API.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

126 lines
3.7 KiB

4 years ago
  1. #!/usr/bin/env python3
  2. '''
  3. pam-custom
  4. Copyright (C) 2013 Loris Tisisno <loris.tissino@gmail.com>
  5. Copyright (C) 2017-2018 Netsyms Technologies <contact@netsyms.com>
  6. This program is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. '''
  17. import os
  18. import requests
  19. import json
  20. import pwd
  21. import crypt
  22. import sys
  23. api_url = "http://localhost/accounthub/api.php"
  24. api_key = "123"
  25. def load_settings():
  26. global api_url
  27. global api_key
  28. if os.path.isfile("/etc/netsyms-business/config.json"):
  29. with open("/etc/netsyms-business/config.json") as f:
  30. text = f.read()
  31. data = json.loads(text)
  32. api_url = data['apiurl']
  33. api_key = data['apikey']
  34. def totp_verify(user, totp):
  35. req = {"key": api_key, "action": "verifytotp", "username": user, "code": totp}
  36. resp = requests.post(api_url, data=req)
  37. if resp.json()['status'] == "OK":
  38. if resp.json()['valid'] == True:
  39. return True
  40. return False
  41. def totp_check(user, pamh):
  42. req = {"key": api_key, "action": "hastotp", "username": user}
  43. resp = requests.post(api_url, data=req)
  44. if resp.json()['status'] == "OK":
  45. if resp.json()['otp'] == True:
  46. otpmsg = pamh.Message(pamh.PAM_PROMPT_ECHO_ON, "Authentication code: ")
  47. rsp = pamh.conversation(otpmsg)
  48. otpcode = rsp.resp
  49. return totp_verify(user, otpcode)
  50. else:
  51. return True
  52. return False
  53. def try_adduser(user, password):
  54. try:
  55. pwd.getpwnam(user)
  56. except KeyError:
  57. print('User ' + user + ' does not exist on this machine, creating...')
  58. # stick this in if you want offline auth, but it isn't updated if the pwd changes in AccountHub
  59. # -p $(mkpasswd -m sha-512 \"" + password + "\")
  60. os.system("useradd -s "+ "/bin/bash "+ "-d "+ "/home/" + user + " -m " + user)
  61. def accounthub_auth(user, password, pamh):
  62. req = {"key": api_key, "action": "auth", "username": user, "password": password}
  63. resp = requests.post(api_url, data=req)
  64. if resp.json()['status'] == "OK":
  65. if totp_check(user, pamh):
  66. try_adduser(user, password)
  67. return True
  68. else:
  69. return False
  70. else:
  71. return False
  72. def pam_sm_authenticate(pamh, flags, argv):
  73. load_settings()
  74. try:
  75. user = pamh.get_user(None)
  76. if user == None:
  77. return pamh.PAM_AUTH_ERR
  78. password = pamh.authtok
  79. if password == None:
  80. ## got no password in authtok - trying through conversation...
  81. passmsg = pamh.Message(pamh.PAM_PROMPT_ECHO_OFF, "Password for " + user + ": ")
  82. rsp = pamh.conversation(passmsg)
  83. password = rsp.resp
  84. # so we should at this point have the password either through the
  85. # prompt or from previous module
  86. if accounthub_auth(user, password, pamh):
  87. return pamh.PAM_SUCCESS
  88. else:
  89. return pamh.PAM_AUTH_ERR
  90. except pamh.exception as e:
  91. return e.pam_result
  92. def pam_sm_setcred(pamh, flags, argv):
  93. return pamh.PAM_SUCCESS
  94. def pam_sm_acct_mgmt(pamh, flags, argv):
  95. return pamh.PAM_SUCCESS
  96. def pam_sm_open_session(pamh, flags, argv):
  97. return pamh.PAM_SUCCESS
  98. def pam_sm_close_session(pamh, flags, argv):
  99. return pamh.PAM_SUCCESS
  100. def pam_sm_chauthtok(pamh, flags, argv):
  101. return pamh.PAM_SUCCESS