Skip to content
This repository has been archived by the owner on Mar 8, 2023. It is now read-only.

Commit

Permalink
Merge branch 'patch_autoenroll'
Browse files Browse the repository at this point in the history
  • Loading branch information
Quentin Lux committed Aug 11, 2020
2 parents 3c431bb + 3f51060 commit 26d8fed
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 9 deletions.
20 changes: 12 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[![Build Status](https://travis-ci.org/privacyidea/pam_python.svg?branch=master)](https://travis-ci.org/privacyidea/pam_python)

This module is to be used with http://pam-python.sourceforge.net/.
It can be used to authenticate with OTP against privacyIDEA. It will also
It can be used to authenticate with OTP against privacyIDEA. It will also
cache future OTP values to enable offline authentication.

To be used like this::
Expand All @@ -10,28 +10,32 @@ To be used like this::

It can take the following parameters:

**url=https://your-server**
**url=https://your-server**

default is https://localhost

**debug**

write debug information to the system log

**realm=yourRealm**

pass additional realm to privacyidea

**nosslverify**

Do not verify the SSL certificate

**prompt=<Prompt>**

The password prompt. Default is "Your OTP".


**api_token=<token>**

The API Token to access admin REST API for auto-enrollment.

**sqlfile=<file>**

This is the SQLite file that is used to store the offline authentication
This is the SQLite file that is used to store the offline authentication
information.
The default file is /etc/privacyidea/pam.sqlite
67 changes: 66 additions & 1 deletion privacyidea_pam.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,15 @@ def __init__(self, pamh, config):
self.sslverify = cacerts
self.realm = config.get("realm")
self.debug = config.get("debug")
self.api_token = config.get("api_token")
self.sqlfile = config.get("sqlfile", "/etc/privacyidea/pam.sqlite")

def make_request(self, data, endpoint="/validate/check"):
def make_request(self, data, endpoint="/validate/check", token=None):
# add a user-agent to be displayed in the Client Application Type
headers = {'user-agent': 'PAM/2.15.0'}
if token:
headers["Authorization"] = token

response = requests.post(self.URL + endpoint, data=data,
headers=headers, verify=self.sslverify)

Expand All @@ -97,6 +101,41 @@ def make_request(self, data, endpoint="/validate/check"):

return json_response

def enroll_user(self, user, pin):
# Generate a new email Token with the provided pin
syslog.syslog(syslog.LOG_DEBUG,
"%s: %s" % (__name__, "Generating a new token"))

data = {"user": self.user,
"genkey": "1",
"pin": pin,
"type": "email",
"dynamic_email": 1}

if self.realm:
data["realm"] = self.realm
json_response = self.make_request(data, endpoint="/token/init", token=self.api_token)

result = json_response.get("result")
detail = json_response.get("detail")

if self.debug:
syslog.syslog(syslog.LOG_DEBUG,
"%s: result: %s" % (__name__, result))
syslog.syslog(syslog.LOG_DEBUG,
"%s: detail: %s" % (__name__, detail))
if result.get("status"):
if result.get("value"):
message = self.pamh.Message(self.pamh.PAM_PROMPT_ECHO_OFF, "Please re-enter your PIN: ")
response = self.pamh.conversation(message)
self.pamh.authtok = response.resp
return self.authenticate(self.pamh.authtok)
else:
syslog.syslog(syslog.LOG_ERR,
"%s: %s" % (__name__,
result.get("error").get("message")))
return self.pamh.PAM_AUTH_ERR

def offline_refill(self, serial, password):

# get refilltoken
Expand Down Expand Up @@ -196,16 +235,39 @@ def authenticate(self, password):
message,
attributes)
else:
<<<<<<< HEAD
syslog.syslog(syslog.LOG_ERR,
"%s: %s" % (__name__, message))
pam_message = self.pamh.Message(self.pamh.PAM_ERROR_MSG, message)
self.pamh.conversation(pam_message)
rval = self.pamh.PAM_AUTH_ERR
=======
if message == 'The user has no tokens assigned':
syslog.syslog(syslog.LOG_DEBUG,
"%s: detail: %s" % (__name__, len(password)))
if len(password)<4:
pam_message = self.pamh.Message(self.pamh.PAM_ERROR_MSG, "You must choose a 4-character minimum PIN.")
self.pamh.conversation(pam_message)
rval = self.pamh.PAM_AUTH_ERR
else:
return self.enroll_user(self.user, password)

else:
syslog.syslog(syslog.LOG_ERR,
"%s: %s" % (__name__, message))
pam_message = self.pamh.Message(self.pamh.PAM_ERROR_MSG, message)
self.pamh.conversation(pam_message)
rval = self.pamh.PAM_AUTH_ERR
>>>>>>> patch_autoenroll
else:
error_msg = result.get("error").get("message")
syslog.syslog(syslog.LOG_ERR,
"%s: %s" % (__name__, error_msg))
<<<<<<< HEAD
pam_message = self.pamh.Message(self.pamh.PAM_ERROR_MSG, error_msg)
=======
pam_message = self.pamh.Message(self.pamh.PAM_ERROR_MSG, str(error_msg))
>>>>>>> patch_autoenroll
self.pamh.conversation(pam_message)

# Save history
Expand Down Expand Up @@ -609,6 +671,7 @@ def _create_table(c):
c.execute("CREATE TABLE IF NOT EXISTS refilltokens (serial text, refilltoken text)")
except sqlite3.OperationalError:
pass
<<<<<<< HEAD

try:
# create history table
Expand All @@ -619,3 +682,5 @@ def _create_table(c):
"ON history (user);")
except sqlite3.OperationalError:
pass
=======
>>>>>>> patch_autoenroll

0 comments on commit 26d8fed

Please sign in to comment.