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 1b89b5a
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 15 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
64 changes: 57 additions & 7 deletions 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,27 @@ def authenticate(self, password):
message,
attributes)
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
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
else:
error_msg = result.get("error").get("message")
syslog.syslog(syslog.LOG_ERR,
"%s: %s" % (__name__, error_msg))
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))
self.pamh.conversation(pam_message)

# Save history
Expand Down

0 comments on commit 1b89b5a

Please sign in to comment.