|
|
@ -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))
|
|
|
|