48
48
import traceback
49
49
import datetime
50
50
import yaml
51
+ import re
51
52
52
53
53
54
def _get_config (argv ):
@@ -70,11 +71,27 @@ def _get_config(argv):
70
71
config [argument [0 ]] = True
71
72
elif len (argument ) == 2 :
72
73
config [argument [0 ]] = argument [1 ]
73
- # Users filter
74
+ # User filter
74
75
if config .get ("users" ) is not None :
75
76
config ["users" ] = config .get ("users" ).split (',' )
76
77
else :
77
78
config ["users" ] = []
79
+ # SQL Connection type/default
80
+ if config .get ("mysql" ) is not None :
81
+ mysql_settings = re .match ("mysql://([^:]+):([^@]+)@([^:/]+):([0-9]+)/(.+)" , config .get ("mysql" ))
82
+ config ["sql" ] = {
83
+ 'lite' : False ,
84
+ 'user' : mysql_settings .group (1 ),
85
+ 'password' : mysql_settings .group (2 ),
86
+ 'host' : mysql_settings .group (3 ),
87
+ 'port' : mysql_settings .group (4 ),
88
+ 'database' : mysql_settings .group (5 )
89
+ }
90
+ else :
91
+ config ["sql" ] = {
92
+ 'lite' : True ,
93
+ 'file' : config .get ("sqlfile" , "/etc/privacyidea/pam.sqlite" )
94
+ }
78
95
return config
79
96
80
97
@@ -94,7 +111,7 @@ def __init__(self, pamh, config):
94
111
self .realm = config .get ("realm" )
95
112
self .debug = config .get ("debug" )
96
113
self .api_token = config .get ("api_token" )
97
- self .sqlfile = config .get ("sqlfile" , "/etc/privacyidea/pam.sqlite " )
114
+ self .sql = config .get ("sql " )
98
115
99
116
def make_request (self , data , endpoint = "/validate/check" ,
100
117
api_token = None , post = True ):
@@ -226,14 +243,14 @@ def enroll_user(self, user):
226
243
def offline_refill (self , serial , password ):
227
244
228
245
# get refilltoken
229
- conn = sqlite3 .connect (self .sqlfile )
230
- c = conn .cursor ()
246
+ startdb (self .sql )
231
247
refilltoken = None
232
248
# get all possible serial/tokens for a user
233
249
for row in c .execute ("SELECT refilltoken FROM refilltokens WHERE serial=?" ,
234
250
(serial , )):
235
251
refilltoken = row [0 ]
236
252
syslog .syslog ("Doing refill with token {0!s}" .format (refilltoken ))
253
+ closedb ()
237
254
238
255
if refilltoken :
239
256
data = {"serial" : serial ,
@@ -253,7 +270,7 @@ def offline_refill(self, serial, password):
253
270
254
271
if result .get ("status" ):
255
272
if result .get ("value" ):
256
- save_auth_item (self .sqlfile , self .user , serial , tokentype ,
273
+ save_auth_item (self .sql , self .user , serial , tokentype ,
257
274
auth_item )
258
275
return True
259
276
else :
@@ -264,13 +281,13 @@ def offline_refill(self, serial, password):
264
281
265
282
def authenticate (self , password ):
266
283
rval = self .pamh .PAM_SYSTEM_ERR
267
- # First we try to authenticate against the sqlitedb
268
- r , serial = check_offline_otp (self .user , password , self .sqlfile , window = 10 )
284
+ # First we try to authenticate against the sqldb
285
+ r , serial = check_offline_otp (self .sql , self .user , password , window = 10 )
269
286
syslog .syslog (syslog .LOG_DEBUG , "offline check returned: {0!s}, {1!s}" .format (r , serial ))
270
287
if r :
271
288
syslog .syslog (syslog .LOG_DEBUG ,
272
289
"%s: successfully authenticated against offline "
273
- "database %s " % (__name__ , self . sqlfile ))
290
+ "database" % (__name__ ))
274
291
275
292
# Try to refill
276
293
try :
@@ -305,7 +322,7 @@ def authenticate(self, password):
305
322
if result .get ("status" ):
306
323
if result .get ("value" ):
307
324
rval = self .pamh .PAM_SUCCESS
308
- save_auth_item (self .sqlfile , self .user , serial , tokentype ,
325
+ save_auth_item (self .sql , self .user , serial , tokentype ,
309
326
auth_item )
310
327
else :
311
328
transaction_id = detail .get ("transaction_id" )
@@ -335,7 +352,7 @@ def authenticate(self, password):
335
352
self .pamh .conversation (pam_message )
336
353
337
354
# Save history
338
- save_history_item (self .sqlfile , self .user , self .rhost , serial ,
355
+ save_history_item (self .sql , self .user , self .rhost , serial ,
339
356
(True if rval == self .pamh .PAM_SUCCESS else False ))
340
357
return rval
341
358
@@ -472,7 +489,7 @@ def pam_sm_authenticate(pamh, flags, argv):
472
489
syslog .syslog (syslog .LOG_DEBUG ,
473
490
"Grace period in minutes: %s " % (str (grace_time )))
474
491
# First we check if grace is authorized
475
- if check_last_history (Auth .sqlfile , Auth .user ,
492
+ if check_last_history (Auth .sql , Auth .user ,
476
493
Auth .rhost , grace_time , window = 10 ):
477
494
rval = pamh .PAM_SUCCESS
478
495
@@ -536,22 +553,21 @@ def pam_sm_chauthtok(pamh, flags, argv):
536
553
return pamh .PAM_SUCCESS
537
554
538
555
539
- def check_offline_otp (user , otp , sqlfile , window = 10 , refill = True ):
556
+ def check_offline_otp (sql_params , user , otp , window = 10 , refill = True ):
540
557
"""
541
558
compare the given otp values with the next hashes of the user.
542
559
543
560
DB entries older than the matching counter will be deleted from the
544
561
database.
545
562
563
+ :param sql_params: MySQL/SQLite connection parameters
564
+ :type sql_params: dict
546
565
:param user: The local user in the sql file
547
566
:param otp: The otp value
548
- :param sqlfile: The sqlite file
549
567
:return: Tuple of (True or False, serial)
550
568
"""
551
569
res = False
552
- conn = sqlite3 .connect (sqlfile )
553
- c = conn .cursor ()
554
- _create_table (c )
570
+ startdb (sql_params )
555
571
# get all possible serial/tokens for a user
556
572
serials = []
557
573
matching_serial = None
@@ -575,22 +591,22 @@ def check_offline_otp(user, otp, sqlfile, window=10, refill=True):
575
591
if res :
576
592
c .execute ("DELETE from authitems WHERE counter <= ? and serial = ?" ,
577
593
(matching_counter , matching_serial ))
578
- conn . commit ()
579
- conn . close ()
594
+
595
+ closedb ()
580
596
return res , matching_serial
581
597
582
598
583
- def save_auth_item (sqlfile , user , serial , tokentype , authitem ):
599
+ def save_auth_item (sql_params , user , serial , tokentype , authitem ):
584
600
"""
585
- Save the given authitem to the sqlite file to be used later for offline
601
+ Save the given authitem to the sqldb file to be used later for offline
586
602
authentication.
587
603
588
604
There is only one table in it with the columns:
589
605
590
606
username, counter, otp
591
607
592
- :param sqlfile: An SQLite file. If it does not exist, it will be generated.
593
- :type sqlfile: basestring
608
+ :param sql_params: MySQL/ SQLite connection parameters
609
+ :type sql_params: dict
594
610
:param user: The PAM user
595
611
:param serial: The serial number of the token
596
612
:param tokentype: The type of the token
@@ -599,10 +615,7 @@ def save_auth_item(sqlfile, user, serial, tokentype, authitem):
599
615
600
616
:return:
601
617
"""
602
- conn = sqlite3 .connect (sqlfile )
603
- c = conn .cursor ()
604
- # Create the table if necessary
605
- _create_table (c )
618
+ startdb (sql_params )
606
619
607
620
syslog .syslog (syslog .LOG_DEBUG , "%s: offline save authitem: %s" % (
608
621
__name__ , authitem ))
@@ -624,33 +637,25 @@ def save_auth_item(sqlfile, user, serial, tokentype, authitem):
624
637
c .execute ("INSERT INTO refilltokens (serial, refilltoken) VALUES (?,?)" ,
625
638
(serial , refilltoken ))
626
639
627
- # Save (commit) the changes
628
- conn .commit ()
640
+ closedb ()
629
641
630
- # We can also close the connection if we are done with it.
631
- # Just be sure any changes have been committed or they will be lost.
632
- conn .close ()
633
-
634
- def check_last_history (sqlfile , user , rhost , grace_time , window = 10 ):
642
+ def check_last_history (sql_params , user , rhost , grace_time , window = 10 ):
635
643
"""
636
644
Get the last event for this user.
637
645
638
646
If success reset the error counter.
639
647
If error increment the error counter.
640
648
641
- :param sqlfile: An SQLite file. If it does not exist, it will be generated.
642
- :type sqlfile: basestring
649
+ :param sql_params: MySQL/ SQLite connection parameters
650
+ :type sql_params: dict
643
651
:param user: The PAM user
644
652
:param rhost: The PAM user rhost value
645
653
:param serial: The serial number of the token
646
654
:param success: Boolean
647
655
648
656
:return:
649
657
"""
650
- conn = sqlite3 .connect (sqlfile , detect_types = sqlite3 .PARSE_DECLTYPES )
651
- c = conn .cursor ()
652
- # Create the table if necessary
653
- _create_table (c )
658
+ startdb (sql_params )
654
659
655
660
res = False
656
661
events = []
@@ -683,31 +688,27 @@ def check_last_history(sqlfile, user, rhost, grace_time, window=10):
683
688
syslog .syslog (syslog .LOG_DEBUG , "%s: No history for: %s" % (
684
689
__name__ , user ))
685
690
686
-
687
- conn .close ()
691
+ closedb ()
688
692
return res
689
693
690
694
691
- def save_history_item (sqlfile , user , rhost , serial , success ):
695
+ def save_history_item (sql_params , user , rhost , serial , success ):
692
696
"""
693
697
Save the given success/error event.
694
698
695
699
If success reset the error counter.
696
700
If error increment the error counter.
697
701
698
- :param sqlfile: An SQLite file. If it does not exist, it will be generated.
699
- :type sqlfile: basestring
702
+ :param sql_params: MySQL/ SQLite connection parameters
703
+ :type sql_params: dict
700
704
:param user: The PAM user
701
705
:param rhost: The PAM user rhost value
702
706
:param serial: The serial number of the token
703
707
:param success: Boolean
704
708
705
709
:return:
706
710
"""
707
- conn = sqlite3 .connect (sqlfile , detect_types = sqlite3 .PARSE_DECLTYPES )
708
- c = conn .cursor ()
709
- # Create the table if necessary
710
- _create_table (c )
711
+ startdb (sql_params )
711
712
712
713
syslog .syslog (syslog .LOG_DEBUG , "%s: offline save event: %s" % (
713
714
__name__ , ("success" if success else "error" )))
@@ -729,39 +730,44 @@ def save_history_item(sqlfile, user, rhost, serial, success):
729
730
"error_counter, last_error) VALUES (?,?,?,?,?)" ,
730
731
(user , rhost , serial , 1 , datetime .datetime .now ()))
731
732
733
+ closedb ()
732
734
733
- # Save (commit) the changes
734
- conn .commit ()
735
735
736
- # We can also close the connection if we are done with it.
737
- # Just be sure any changes have been committed or they will be lost.
738
- conn .close ()
736
+ # Start connection and create cursor
737
+ def startdb (sql_params ):
738
+ global conn , c
739
+ # Create connection
740
+ if sql_params ["lite" ]:
741
+ conn = sqlite3 .connect (sql_params ["file" ], detect_types = sqlite3 .PARSE_DECLTYPES )
742
+ # Create a cursor object
743
+ c = conn .cursor ()
744
+ else :
745
+ print ("Mysql" )
746
+ # mysql.connector.connect(**connection_config_dict)
747
+
748
+ # Create table if does not exist
749
+ _create_table ()
739
750
751
+ # Commit and close db
752
+ def closedb ():
753
+ # Commit changes
754
+ conn .commit ()
755
+ # Close connections
756
+ conn .close ()
740
757
741
- def _create_table (c ):
758
+ def _create_table ():
742
759
"""
743
760
Create table if necessary
744
761
:param c: The connection cursor
745
762
"""
746
- try :
747
- c .execute ("CREATE TABLE IF NOT EXISTS authitems "
748
- "(counter int, user text, serial text, tokenowner text,"
749
- "otp text, tokentype text)" )
750
- except sqlite3 .OperationalError :
751
- pass
752
-
753
- try :
754
- # create refilltokens table
755
- c .execute ("CREATE TABLE IF NOT EXISTS refilltokens (serial text, refilltoken text)" )
756
- except sqlite3 .OperationalError :
757
- pass
758
-
759
- try :
760
- # create history table
761
- c .execute ("CREATE TABLE IF NOT EXISTS history "
762
- "(user text, rhost text, serial text, error_counter int, "
763
- "last_success timestamp, last_error timestamp)" )
764
- c .execute ("CREATE UNIQUE INDEX idx_user "
765
- "ON history (user, rhost);" )
766
- except sqlite3 .OperationalError :
767
- pass
763
+ c .execute ("CREATE TABLE IF NOT EXISTS authitems "
764
+ "(counter int, user text, serial text, tokenowner text,"
765
+ "otp text, tokentype text)" )
766
+ # create refilltokens table
767
+ c .execute ("CREATE TABLE IF NOT EXISTS refilltokens (serial text, refilltoken text)" )
768
+ # create history table
769
+ c .execute ("CREATE TABLE IF NOT EXISTS history "
770
+ "(user text, rhost text, serial text, error_counter int, "
771
+ "last_success timestamp, last_error timestamp)" )
772
+ c .execute ("CREATE UNIQUE INDEX idx_user "
773
+ "ON history (user, rhost);" )
0 commit comments