Skip to content

Commit 9cdfdfb

Browse files
author
Nicolas Beguier
committed
CASSH Server v1.4.2: Add more LDAP error msg AND increase sql req security
1 parent 856ba01 commit 9cdfdfb

File tree

1 file changed

+72
-48
lines changed

1 file changed

+72
-48
lines changed

server/server.py

Lines changed: 72 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
'/test_auth', 'TestAuth',
4242
)
4343

44-
VERSION = '1.4.1'
44+
VERSION = '1.4.2'
4545

4646
PARSER = ArgumentParser()
4747
PARSER.add_argument('-c', '--config', action='store', help='Configuration file')
@@ -178,8 +178,8 @@ def sign_key(tmp_pubkey_name, username, expiry, principals, db_cursor=None):
178178
cert_contents = ca_ssh.sign_public_user_key(\
179179
tmp_pubkey_name, username, expiry, principals)
180180
if db_cursor is not None:
181-
db_cursor.execute("""UPDATE USERS SET STATE=0, EXPIRATION=%s WHERE NAME='%s'"""\
182-
% (time() + str2date(expiry), username))
181+
db_cursor.execute('UPDATE USERS SET STATE=0, EXPIRATION=(%s) WHERE NAME=(%s)', \
182+
(time() + str2date(expiry), username))
183183
except:
184184
cert_contents = 'Error : signing key'
185185
return cert_contents
@@ -196,13 +196,13 @@ def list_keys(username=None, realname=None):
196196
is_list = False
197197

198198
if realname is not None:
199-
cur.execute("""SELECT * FROM USERS WHERE lower(REALNAME)=lower('%s')""" % realname)
199+
cur.execute('SELECT * FROM USERS WHERE REALNAME=lower((%s))', (realname,))
200200
result = cur.fetchone()
201201
elif username is not None:
202-
cur.execute("""SELECT * FROM USERS WHERE NAME='%s'""" % username)
202+
cur.execute('SELECT * FROM USERS WHERE NAME=(%s)', (username,))
203203
result = cur.fetchone()
204204
else:
205-
cur.execute("""SELECT * FROM USERS""")
205+
cur.execute('SELECT * FROM USERS')
206206
result = cur.fetchall()
207207
is_list = True
208208
cur.close()
@@ -220,25 +220,25 @@ def ldap_authentification(admin=False):
220220
if web_input().has_key('realname'):
221221
realname = web_input()['realname']
222222
else:
223-
return False
223+
return False, 'Error: No realname option given.'
224224

225225
if web_input().has_key('password'):
226226
password = web_input()['password']
227227
else:
228-
return False
228+
return False, 'Error: No password option given.'
229229
if password == '':
230-
return False
230+
return False, 'Error: password is empty.'
231231
ldap_conn = ldap_open(SERVER_OPTS['ldap_host'])
232232
try:
233233
ldap_conn.bind_s(realname, password)
234-
except:
235-
return False
234+
except Exception as e:
235+
return False, 'Error: %s' % e
236236
if admin and SERVER_OPTS['ldap_admin_cn'] not in\
237237
ldap_conn.search_s(SERVER_OPTS['ldap_bind_dn'], 2,
238238
filterstr='(%s=%s)' % (SERVER_OPTS['filterstr'], realname)
239239
)[0][1]['memberOf']:
240-
return False
241-
return True
240+
return False, 'Error: user %s is not an admin.' % realname
241+
return True, 'OK'
242242

243243
def check_input():
244244
"""
@@ -271,9 +271,10 @@ def GET(self, username):
271271
if not check_input():
272272
return 'Error : Wrong inputs.'
273273

274-
if not ldap_authentification(admin=True):
275-
return 'Error : Authentication'
276-
274+
# LDAP authentication
275+
is_admin_auth, message = ldap_authentification(admin=True)
276+
if not is_admin_auth:
277+
return message
277278

278279
if web_input().has_key('revoke'):
279280
do_revoke = web_input()['revoke'] == 'true'
@@ -293,20 +294,20 @@ def GET(self, username):
293294
return list_keys()
294295

295296
# Search if key already exists
296-
cur.execute("""SELECT * FROM USERS WHERE NAME='%s'""" % username)
297+
cur.execute('SELECT * FROM USERS WHERE NAME=(%s)', (username,))
297298
user = cur.fetchone()
298299
# If user dont exist
299300
if user is None:
300301
cur.close()
301302
pg_conn.close()
302303
message = "User '%s' does not exists." % username
303304
elif do_revoke:
304-
cur.execute("""UPDATE USERS SET STATE=1 WHERE NAME = '%s'""" % username)
305+
cur.execute('UPDATE USERS SET STATE=1 WHERE NAME=(%s)', (username,))
305306
pg_conn.commit()
306307
message = 'Revoke user=%s.' % username
307308
# Load SSH CA and revoke key
308309
ca_ssh = Authority(SERVER_OPTS['ca'], SERVER_OPTS['krl'])
309-
cur.execute("""SELECT SSH_KEY FROM USERS WHERE NAME = '%s'""" % username)
310+
cur.execute('SELECT SSH_KEY FROM USERS WHERE NAME=(%s)', (username,))
310311
pubkey = cur.fetchone()[0]
311312
tmp_pubkey = NamedTemporaryFile(delete=False)
312313
tmp_pubkey.write(pubkey)
@@ -320,14 +321,14 @@ def GET(self, username):
320321
return list_keys(username=username)
321322
# If user is in PENDING state
322323
elif user[2] == 2:
323-
cur.execute("""UPDATE USERS SET STATE=0 WHERE NAME = '%s'""" % username)
324+
cur.execute('UPDATE USERS SET STATE=0 WHERE NAME=(%s)', (username,))
324325
pg_conn.commit()
325326
cur.close()
326327
pg_conn.close()
327328
message = 'Active user=%s. SSH Key active but need to be signed.' % username
328329
# If user is in REVOKE state
329330
elif user[2] == 1:
330-
cur.execute("""UPDATE USERS SET STATE=0 WHERE NAME = '%s'""" % username)
331+
cur.execute('UPDATE USERS SET STATE=0 WHERE NAME=(%s)', (username,))
331332
pg_conn.commit()
332333
cur.close()
333334
pg_conn.close()
@@ -351,8 +352,10 @@ def POST(self, username):
351352
if not check_input():
352353
return 'Error : Wrong inputs.'
353354

354-
if not ldap_authentification(admin=True):
355-
return 'Error : Authentication'
355+
# LDAP authentication
356+
is_admin_auth, message = ldap_authentification(admin=True)
357+
if not is_admin_auth:
358+
return message
356359

357360
pg_conn, message = pg_connection()
358361
if pg_conn is None:
@@ -366,15 +369,18 @@ def POST(self, username):
366369
if pattern.match(value) is None:
367370
return 'ERROR: Value %s is malformed. Should match pattern ^\+([0-9]+)+d$' \
368371
% value
369-
cur.execute("""UPDATE USERS SET EXPIRY='%s' WHERE NAME='%s'""" \
370-
% (value, username))
372+
cur.execute('UPDATE USERS SET EXPIRY=(%s) WHERE NAME=(%s)', (value, username))
371373
pg_conn.commit()
372374
cur.close()
373375
pg_conn.close()
374376
return 'OK: %s=%s for %s' % (key, value, username)
375377
elif key == 'principals':
376-
cur.execute("""UPDATE USERS SET PRINCIPALS='%s' WHERE NAME='%s'""" \
377-
% (value, username))
378+
pattern = re_compile("^([a-zA-Z]+)$")
379+
for principal in value.split(','):
380+
if pattern.match(principal) is None:
381+
return 'ERROR: Value %s is malformed. Should match pattern ^([a-zA-Z]+)$' \
382+
% principal
383+
cur.execute('UPDATE USERS SET PRINCIPALS=(%s) WHERE NAME=(%s)', (value, username))
378384
pg_conn.commit()
379385
cur.close()
380386
pg_conn.close()
@@ -385,16 +391,23 @@ def POST(self, username):
385391
def DELETE(self, username):
386392
"""
387393
Delete keys (but DOESN'T REVOKE)
394+
/admin/<username>
395+
# Auth params:
396+
realname=xxxxx@domain.fr
397+
password=xxxxx
388398
"""
389-
if not ldap_authentification(admin=True):
390-
return 'Error : Authentication'
399+
# LDAP authentication
400+
is_admin_auth, message = ldap_authentification(admin=True)
401+
if not is_admin_auth:
402+
return message
403+
391404
pg_conn, message = pg_connection()
392405
if pg_conn is None:
393406
return message
394407
cur = pg_conn.cursor()
395408

396409
# Search if key already exists
397-
cur.execute("""DELETE FROM USERS WHERE NAME='%s'""" % username, )
410+
cur.execute('DELETE FROM USERS WHERE NAME=(%s)', (username,))
398411
pg_conn.commit()
399412
cur.close()
400413
pg_conn.close()
@@ -428,8 +441,10 @@ def GET(self):
428441
if not check_input():
429442
return 'Error : Wrong inputs.'
430443

431-
if not ldap_authentification():
432-
return 'Error : Authentication'
444+
# LDAP authentication
445+
is_auth, message = ldap_authentification()
446+
if not is_auth:
447+
return message
433448

434449
if web_input().has_key('realname'):
435450
realname = web_input()['realname']
@@ -457,12 +472,17 @@ def POST(self):
457472
return 'Error : Wrong inputs.'
458473

459474
# LDAP authentication
460-
if not ldap_authentification():
461-
return 'Error : Authentication'
475+
is_auth, message = ldap_authentification()
476+
if not is_auth:
477+
return message
462478

463479
# Check if user is an admin and want to force signature when db fail
464480
force_sign = False
465-
if ldap_authentification(admin=True) and SERVER_OPTS['admin_db_failover'] \
481+
482+
# LDAP ADMIN authentication
483+
is_admin_auth, _ = ldap_authentification(admin=True)
484+
485+
if is_admin_auth and SERVER_OPTS['admin_db_failover'] \
466486
and 'admin_force' in web_input() and web_input()['admin_force'] == 'true':
467487
force_sign = True
468488

@@ -505,8 +525,7 @@ def POST(self):
505525
cur = pg_conn.cursor()
506526

507527
# Search if key already exists
508-
cur.execute("""SELECT * FROM USERS WHERE SSH_KEY='%s' AND name=lower('%s')""" \
509-
% (pubkey, username))
528+
cur.execute('SELECT * FROM USERS WHERE SSH_KEY=(%s) AND NAME=lower(%s)', (pubkey, username))
510529
user = cur.fetchone()
511530
if user is None:
512531
cur.close()
@@ -551,8 +570,10 @@ def PUT(self):
551570
if not check_input():
552571
return 'Error : Wrong inputs.'
553572

554-
if not ldap_authentification():
555-
return 'Error : Authentication'
573+
# LDAP authentication
574+
is_auth, message = ldap_authentification()
575+
if not is_auth:
576+
return message
556577

557578
if web_input().has_key('username'):
558579
username = web_input()['username']
@@ -585,31 +606,32 @@ def PUT(self):
585606
cur = pg_conn.cursor()
586607

587608
# Search if key already exists
588-
cur.execute("""SELECT * FROM USERS WHERE NAME='%s'""" % username)
609+
cur.execute('SELECT * FROM USERS WHERE NAME=(%s)', (username,))
589610
user = cur.fetchone()
590611

591612
# CREATE NEW USER
592613
if user is None:
593-
cur.execute("""INSERT INTO USERS VALUES ('%s', '%s', %s, %s, '%s', '%s', '+1d', '')""" \
594-
% (username, realname, 2, 0, pubkey_fingerprint, pubkey))
614+
cur.execute('INSERT INTO USERS VALUES \
615+
((%s), (%s), (%s), (%s), (%s), (%s), (%s), (%s))', \
616+
(username, realname, 2, 0, pubkey_fingerprint, pubkey, '+1d', ''))
595617
pg_conn.commit()
596618
cur.close()
597619
pg_conn.close()
598620
remove(tmp_pubkey.name)
599621
return 'Create user=%s. Pending request.' % username
600622
else:
601623
# Check if realname is the same
602-
cur.execute("""SELECT * FROM USERS WHERE NAME='%s' AND lower(REALNAME)=lower('%s')"""\
603-
% (username, realname))
624+
cur.execute('SELECT * FROM USERS WHERE NAME=(%s) AND REALNAME=lower((%s))', \
625+
(username, realname))
604626
if cur.fetchone() is None:
605627
pg_conn.commit()
606628
cur.close()
607629
pg_conn.close()
608630
remove(tmp_pubkey.name)
609631
return 'Error : (username, realname) couple mismatch.'
610632
# Update entry into database
611-
cur.execute("""UPDATE USERS SET SSH_KEY='%s', SSH_KEY_HASH='%s', STATE=2, EXPIRATION=0 \
612-
WHERE NAME = '%s'""" % (pubkey, pubkey_fingerprint, username))
633+
cur.execute('UPDATE USERS SET SSH_KEY=(%s), SSH_KEY_HASH=(%s), STATE=2, EXPIRATION=0 \
634+
WHERE NAME=(%s)', (pubkey, pubkey_fingerprint, username))
613635
pg_conn.commit()
614636
cur.close()
615637
pg_conn.close()
@@ -661,8 +683,10 @@ def GET(self):
661683
"""
662684
Test authentication
663685
"""
664-
if not ldap_authentification():
665-
return 'Error : Authentication'
686+
# LDAP authentication
687+
is_auth, message = ldap_authentification()
688+
if not is_auth:
689+
return message
666690
return 'OK'
667691

668692

0 commit comments

Comments
 (0)