SQL-based authentication: Difference between revisions

Content added Content deleted
(→‎{{header|Python}}: Fixed SQL injection; changed library to the official one; fixed some other issues)
(Added racket implementation)
Line 537: Line 537:
print 'User %s failed' % user
print 'User %s failed' % user
</lang>
</lang>

=={{header|Racket}}==

<lang racket>#lang racket
(require db file/md5)
(define-logger authentication)
(current-logger authentication-logger)

(define DB-HOST "localhost")
(define DB-USER "devel")
(define DB-PASS "devel")
(define DB-NAME "test")

(define (connect-db)
(mysql-connect
#:user DB-USER
#:database DB-NAME
#:password DB-PASS))

(define (salt+password->hash salt password #:hex-encode? (hex-encode? #f))
(md5 (bytes-append salt password) hex-encode?))

(define (report-sql-error e)
(log-authentication-error "Failed to create user:~s" (exn-message e))
#f)

(define (create-user db username passwd)
; if user was successfully created, returns its ID else #f
(define salt (list->bytes (for/list ((i (in-range 16))) (random 256))))
(define hash (salt+password->hash salt passwd))
(with-handlers ((exn:fail:sql? report-sql-error))
(query db "INSERT INTO users (username, pass_salt, pass_md5) VALUES (?, ?, ?)"
username salt hash)))

; returns an
(define (authenticate-user db username password)
(or
(match (query-maybe-row db "SELECT pass_salt, pass_md5 FROM users WHERE username = ?" username)
[#f #f]
[(vector salt hash) (bytes=? hash (salt+password->hash salt password))])
; don't let the deviants know whether it's the username or password that's dodgy
(error "the username, password combination does not exist in system")))

(module+ test
(require rackunit)
(define test-DB (connect-db))
; typically, you only do this the once (or risk upsetting your users bigtime!)
; call this just the once!
(define (create-users-table db)
(query-exec db "DROP TABLE IF EXISTS users")
(query-exec db #<<EOS
CREATE TABLE users (
userid INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(32) UNIQUE KEY NOT NULL,
pass_salt tinyblob NOT NULL,
-- a string of 16 random bytes
pass_md5 tinyblob NOT NULL
-- binary MD5 hash of pass_salt concatenated with the password
);
EOS
))
(create-users-table test-DB)
(create-user test-DB #"tim" #"shh! it's a secret!")
; ensure the user exists (for testing purposes)
(check-match (query-list test-DB "SELECT userid FROM users WHERE username = 'tim'") (list _))
; (ah... but tim exists!!!)
(check-false (create-user test-DB #"tim" #"tim's password"))
(check-exn exn:fail? (λ () (authenticate-user test-DB #"tim" #"password")))
(check-true (authenticate-user test-DB #"tim" #"shh! it's a secret!")))</lang>


=={{header|Raven}}==
=={{header|Raven}}==