Initial version.

master
Thomas Hintz 11 years ago
parent e89a257a5c
commit a473f0a337

@ -3,6 +3,11 @@
(:export #:pg-session (:export #:pg-session
#:pg-session-id #:pg-session-id
#:pg-session-gc #:pg-session-gc
#:pg-remove-session
#:*session-type*
#:*database-connection-spec*
#:pg-session-value
#:pg-session-max-time
#:pg-start-session #:pg-start-session
#:save-pg-session)) #:save-pg-session))

@ -27,8 +27,9 @@
(in-package #:pg-sessions) (in-package #:pg-sessions)
(defparameter *hunchentoot-postmodern-session-max-time* 3600) ; 1 hour (defparameter *pg-session-max-time* 3600) ; 1 hour
(defvar *pg-session-secret* "thisisasecret") (defvar *pg-session-secret* "thisisasecret")
(defparameter *database-connection-spec* nil)
(defclass pg-session () (defclass pg-session ()
((session-id :col-type serial :initarg :session-id :reader pg-session-id) ((session-id :col-type serial :initarg :session-id :reader pg-session-id)
@ -44,7 +45,7 @@ cookie value or as a GET parameter.")
(last-click :col-type bigint :initform (get-universal-time) :accessor pg-session-last-click (last-click :col-type bigint :initform (get-universal-time) :accessor pg-session-last-click
:documentation "The last time this session was used.") :documentation "The last time this session was used.")
(max-time :col-type bigint :initarg :max-time (max-time :col-type bigint :initarg :max-time
:initform *hunchentoot-postmodern-session-max-time* :initform *pg-session-max-time*
:accessor pg-session-max-time :accessor pg-session-max-time
:documentation "The time \(in seconds) after which this :documentation "The time \(in seconds) after which this
session expires if it's not used.")) session expires if it's not used."))
@ -53,6 +54,8 @@ session expires if it's not used."))
(:documentation "An extensions of hunchentoot's sessions so that sessions can be (:documentation "An extensions of hunchentoot's sessions so that sessions can be
stored in the postmodern database.")) stored in the postmodern database."))
(defparameter *session-type* 'pg-session)
(defun md5-hex (string) (defun md5-hex (string)
"Calculates the md5 sum of the string STRING and returns it as a hex string." "Calculates the md5 sum of the string STRING and returns it as a hex string."
(with-output-to-string (s) (with-output-to-string (s)
@ -64,11 +67,7 @@ stored in the postmodern database."))
USER-AGENT, and START" USER-AGENT, and START"
;; *PG-SESSION-SECRET* is used twice due to known theoretical ;; *PG-SESSION-SECRET* is used twice due to known theoretical
;; vulnerabilities of MD5 encoding ;; vulnerabilities of MD5 encoding
(hunchentoot:log-message* :info "UA: ~A" user-agent) (md5-hex (concatenate 'string
(hunchentoot:log-message* :info "addr: ~A" remote-addr)
(hunchentoot:log-message* :info "start: ~A" start)
(hunchentoot:log-message* :info "id: ~A" id)
(let ((r (md5-hex (concatenate 'string
*pg-session-secret* *pg-session-secret*
(md5-hex (format nil "~A~A~@[~A~]~@[~A~]~A" (md5-hex (format nil "~A~A~@[~A~]~@[~A~]~A"
*pg-session-secret* *pg-session-secret*
@ -77,16 +76,11 @@ USER-AGENT, and START"
user-agent) user-agent)
(and hunchentoot:*use-remote-addr-for-sessions* (and hunchentoot:*use-remote-addr-for-sessions*
remote-addr) remote-addr)
start)))))) start)))))
(hunchentoot:log-message* :info "encoding: ~A" r)
r))
(defun stringify-session (session) (defun stringify-session (session)
"Creates a string representing of the SESSION object SESSION. See "Creates a string representing of the SESSION object SESSION. See
ENCODE-SESSION-STRING." ENCODE-SESSION-STRING."
(hunchentoot:log-message* :info "UA: ~A" (pg-session-user-agent session))
(hunchentoot:log-message* :info "addr: ~A" (pg-session-remote-addr session))
(hunchentoot:log-message* :info "start: ~A" (pg-session-start session))
(encode-session-string (pg-session-id session) (encode-session-string (pg-session-id session)
(pg-session-user-agent session) (pg-session-user-agent session)
(pg-session-remote-addr session) (pg-session-remote-addr session)
@ -96,7 +90,7 @@ ENCODE-SESSION-STRING."
(< (+ (pg-session-last-click session) (pg-session-max-time session)) (< (+ (pg-session-last-click session) (pg-session-max-time session))
(get-universal-time))) (get-universal-time)))
(defun pg-remove-session (session) (defun pg-remove-session (&optional (session hunchentoot:*session*))
"Completely removes the SESSION object SESSION from Hunchentoot's "Completely removes the SESSION object SESSION from Hunchentoot's
internal session database." internal session database."
(delete-dao session) (delete-dao session)
@ -105,35 +99,36 @@ internal session database."
(defun pg-session-gc () (defun pg-session-gc ()
"Removes sessions from the current session database which are too "Removes sessions from the current session database which are too
old - see SESSION-TOO-OLD-P." old - see SESSION-TOO-OLD-P."
(loop for session in (select-dao 'pg-session) (loop for session in (select-dao *session-type*)
when (session-too-old-p session) when (session-too-old-p session)
do (remove-session session))) do (remove-session session)))
(defmethod hunchentoot:session-cookie-value ((pg-session pg-session)) (defmethod hunchentoot:session-cookie-value ((pg-session pg-session))
(hunchentoot:log-message* :warning "session verify")
(and pg-session (and pg-session
(format nil (format nil
"~D:~A" "~D:~A"
(pg-session-id pg-session) (pg-session-id pg-session)
(pg-session-string pg-session)))) (pg-session-string pg-session))))
(defun save-pg-session (session) (defun save-pg-session (&optional (session hunchentoot:*session*))
(upsert-dao session)) (upsert-dao session))
(defun pg-start-session () (defun pg-start-session (&rest args)
"Returns the current SESSION object. If there is no current session, "Returns the current SESSION object. If there is no current session,
creates one and updates the corresponding data structures. In this creates one and updates the corresponding data structures. In this
case the function will also send a session cookie to the browser." case the function will also send a session cookie to the browser."
(hunchentoot:log-message* :info "in pg-start-session")
(let ((session (hunchentoot:session hunchentoot:*request*))) (let ((session (hunchentoot:session hunchentoot:*request*)))
(when session (when session
(return-from pg-start-session session)) (return-from pg-start-session session))
(hunchentoot:log-message* :info "session before") (setf session
(setf session (make-dao 'pg-session (apply #'make-dao
:user-agent (hunchentoot:user-agent hunchentoot:*request*) (append `(,*session-type*
:remote-addr (hunchentoot:real-remote-addr hunchentoot:*request*))) :user-agent ,(hunchentoot:user-agent hunchentoot:*request*)
(hunchentoot:log-message* :info "session ~S" session) :remote-addr ,(hunchentoot:real-remote-addr hunchentoot:*request*))
(hunchentoot:log-message* :info "session-id: ~A" (pg-session-id session)) args)))
;; (setf session (make-dao *session-type*
;; :user-agent (hunchentoot:user-agent hunchentoot:*request*)
;; :remote-addr (hunchentoot:real-remote-addr hunchentoot:*request*)))
(setf (hunchentoot:session hunchentoot:*request*) session) (setf (hunchentoot:session hunchentoot:*request*) session)
(setf (pg-session-string session) (stringify-session session)) (setf (pg-session-string session) (stringify-session session))
(save-pg-session session) (save-pg-session session)
@ -146,11 +141,7 @@ case the function will also send a session cookie to the browser."
"Returns the SESSION object corresponding to the number ID if the "Returns the SESSION object corresponding to the number ID if the
session has not expired. Will remove the session if it has expired but session has not expired. Will remove the session if it has expired but
will not create a new one." will not create a new one."
(hunchentoot:log-message* :info "get-stored-session ~A" id) (let ((session (get-dao *session-type* id)))
(hunchentoot:log-message* :info "request ~S" request)
(let ((session (get-dao 'pg-session id)))
(hunchentoot:log-message* :info "get-stored-session ~A recieved" id)
(hunchentoot:log-message* :info "session: ~A" session)
(when (and session (when (and session
(session-too-old-p session)) (session-too-old-p session))
(when hunchentoot:*reply* (when hunchentoot:*reply*
@ -158,16 +149,13 @@ will not create a new one."
(pg-remove-session session) (pg-remove-session session)
(setq session nil)) (setq session nil))
(when session (when session
(hunchentoot:log-message* :info "setting stuff")
(setf (pg-session-user-agent session) (hunchentoot:user-agent request) (setf (pg-session-user-agent session) (hunchentoot:user-agent request)
(pg-session-remote-addr session) (hunchentoot:real-remote-addr request))) (pg-session-remote-addr session) (hunchentoot:real-remote-addr request)))
session)) session))
(defmethod hunchentoot:session-verify ((request hunchentoot:request)) (defmethod hunchentoot:session-verify ((request hunchentoot:request))
(hunchentoot:log-message* :info "session verify")
(hunchentoot:log-message* :warning "UNCOMMENT remove session in faked")
(with-connection (with-connection
'("foods" "tjhintz" "" "localhost" :pooled-p t) *database-connection-spec*
(with-transaction (transaction) (with-transaction (transaction)
(let ((session-identifier (let ((session-identifier
(or (when-let (session-cookie (hunchentoot:cookie-in (or (when-let (session-cookie (hunchentoot:cookie-in
@ -208,7 +196,7 @@ will not create a new one."
;; remove the session to make sure that it can't be used ;; remove the session to make sure that it can't be used
;; again; the original legitimate user will be required to ;; again; the original legitimate user will be required to
;; log in again ;; log in again
;; (pg-remove-session session) (pg-remove-session session)
nil) nil)
(t (t
;; no session was found under the ID given, presumably ;; no session was found under the ID given, presumably
@ -218,6 +206,19 @@ will not create a new one."
session-identifier user-agent remote-addr) session-identifier user-agent remote-addr)
nil)))))))) nil))))))))
(defun pg-session-value (symbol &optional (session hunchentoot:*session*))
"Returns the value associated with SYMBOL from the session object
SESSION \(the default is the current session) if it exists."
(when session
(slot-value session symbol)))
(defsetf pg-session-value (symbol &optional session) (new-value)
(with-gensyms (%session %symbol)
`(let ((,%session (or ,session (pg-start-session)))
(,%symbol ,symbol))
(setf (slot-value ,%session ,%symbol) ,new-value)
(save-pg-session ,%session))))
;; (defun reset-sessions (&optional (acceptor *acceptor*)) ;; (defun reset-sessions (&optional (acceptor *acceptor*))
;; "Removes ALL stored sessions of ACCEPTOR." ;; "Removes ALL stored sessions of ACCEPTOR."
;; (with-session-lock-held ((session-db-lock acceptor)) ;; (with-session-lock-held ((session-db-lock acceptor))

Loading…
Cancel
Save