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

Commit 26d8fed

Browse files
author
Quentin Lux
committed
Merge branch 'patch_autoenroll'
2 parents 3c431bb + 3f51060 commit 26d8fed

File tree

2 files changed

+78
-9
lines changed

2 files changed

+78
-9
lines changed

README.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[![Build Status](https://travis-ci.org/privacyidea/pam_python.svg?branch=master)](https://travis-ci.org/privacyidea/pam_python)
22

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

77
To be used like this::
@@ -10,28 +10,32 @@ To be used like this::
1010

1111
It can take the following parameters:
1212

13-
**url=https://your-server**
13+
**url=https://your-server**
1414

1515
default is https://localhost
16-
16+
1717
**debug**
1818

1919
write debug information to the system log
20-
20+
2121
**realm=yourRealm**
2222

2323
pass additional realm to privacyidea
24-
24+
2525
**nosslverify**
2626

2727
Do not verify the SSL certificate
28-
28+
2929
**prompt=<Prompt>**
3030

3131
The password prompt. Default is "Your OTP".
32-
32+
33+
**api_token=<token>**
34+
35+
The API Token to access admin REST API for auto-enrollment.
36+
3337
**sqlfile=<file>**
3438

35-
This is the SQLite file that is used to store the offline authentication
39+
This is the SQLite file that is used to store the offline authentication
3640
information.
3741
The default file is /etc/privacyidea/pam.sqlite

privacyidea_pam.py

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,15 @@ def __init__(self, pamh, config):
8282
self.sslverify = cacerts
8383
self.realm = config.get("realm")
8484
self.debug = config.get("debug")
85+
self.api_token = config.get("api_token")
8586
self.sqlfile = config.get("sqlfile", "/etc/privacyidea/pam.sqlite")
8687

87-
def make_request(self, data, endpoint="/validate/check"):
88+
def make_request(self, data, endpoint="/validate/check", token=None):
8889
# add a user-agent to be displayed in the Client Application Type
8990
headers = {'user-agent': 'PAM/2.15.0'}
91+
if token:
92+
headers["Authorization"] = token
93+
9094
response = requests.post(self.URL + endpoint, data=data,
9195
headers=headers, verify=self.sslverify)
9296

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

98102
return json_response
99103

104+
def enroll_user(self, user, pin):
105+
# Generate a new email Token with the provided pin
106+
syslog.syslog(syslog.LOG_DEBUG,
107+
"%s: %s" % (__name__, "Generating a new token"))
108+
109+
data = {"user": self.user,
110+
"genkey": "1",
111+
"pin": pin,
112+
"type": "email",
113+
"dynamic_email": 1}
114+
115+
if self.realm:
116+
data["realm"] = self.realm
117+
json_response = self.make_request(data, endpoint="/token/init", token=self.api_token)
118+
119+
result = json_response.get("result")
120+
detail = json_response.get("detail")
121+
122+
if self.debug:
123+
syslog.syslog(syslog.LOG_DEBUG,
124+
"%s: result: %s" % (__name__, result))
125+
syslog.syslog(syslog.LOG_DEBUG,
126+
"%s: detail: %s" % (__name__, detail))
127+
if result.get("status"):
128+
if result.get("value"):
129+
message = self.pamh.Message(self.pamh.PAM_PROMPT_ECHO_OFF, "Please re-enter your PIN: ")
130+
response = self.pamh.conversation(message)
131+
self.pamh.authtok = response.resp
132+
return self.authenticate(self.pamh.authtok)
133+
else:
134+
syslog.syslog(syslog.LOG_ERR,
135+
"%s: %s" % (__name__,
136+
result.get("error").get("message")))
137+
return self.pamh.PAM_AUTH_ERR
138+
100139
def offline_refill(self, serial, password):
101140

102141
# get refilltoken
@@ -196,16 +235,39 @@ def authenticate(self, password):
196235
message,
197236
attributes)
198237
else:
238+
<<<<<<< HEAD
199239
syslog.syslog(syslog.LOG_ERR,
200240
"%s: %s" % (__name__, message))
201241
pam_message = self.pamh.Message(self.pamh.PAM_ERROR_MSG, message)
202242
self.pamh.conversation(pam_message)
203243
rval = self.pamh.PAM_AUTH_ERR
244+
=======
245+
if message == 'The user has no tokens assigned':
246+
syslog.syslog(syslog.LOG_DEBUG,
247+
"%s: detail: %s" % (__name__, len(password)))
248+
if len(password)<4:
249+
pam_message = self.pamh.Message(self.pamh.PAM_ERROR_MSG, "You must choose a 4-character minimum PIN.")
250+
self.pamh.conversation(pam_message)
251+
rval = self.pamh.PAM_AUTH_ERR
252+
else:
253+
return self.enroll_user(self.user, password)
254+
255+
else:
256+
syslog.syslog(syslog.LOG_ERR,
257+
"%s: %s" % (__name__, message))
258+
pam_message = self.pamh.Message(self.pamh.PAM_ERROR_MSG, message)
259+
self.pamh.conversation(pam_message)
260+
rval = self.pamh.PAM_AUTH_ERR
261+
>>>>>>> patch_autoenroll
204262
else:
205263
error_msg = result.get("error").get("message")
206264
syslog.syslog(syslog.LOG_ERR,
207265
"%s: %s" % (__name__, error_msg))
266+
<<<<<<< HEAD
208267
pam_message = self.pamh.Message(self.pamh.PAM_ERROR_MSG, error_msg)
268+
=======
269+
pam_message = self.pamh.Message(self.pamh.PAM_ERROR_MSG, str(error_msg))
270+
>>>>>>> patch_autoenroll
209271
self.pamh.conversation(pam_message)
210272

211273
# Save history
@@ -609,6 +671,7 @@ def _create_table(c):
609671
c.execute("CREATE TABLE IF NOT EXISTS refilltokens (serial text, refilltoken text)")
610672
except sqlite3.OperationalError:
611673
pass
674+
<<<<<<< HEAD
612675

613676
try:
614677
# create history table
@@ -619,3 +682,5 @@ def _create_table(c):
619682
"ON history (user);")
620683
except sqlite3.OperationalError:
621684
pass
685+
=======
686+
>>>>>>> patch_autoenroll

0 commit comments

Comments
 (0)