[hunchentoot-devel] Re: session shearing question

Andrea Chiumenti kiuma72 at gmail.com
Tue Jan 8 09:12:50 UTC 2008


Hi Edi,
are you interested in these modifications ?


(defgeneric request-realm (req)
  (:documentation "Returns the realm under which the request has been sent.
A realm is used to group resources under a common 'place', and is used for
registered web applications
to have different or common sessions for a give user."))
(defgeneric (setf request-realm) (value req)
  (:documentation "Sets the realm under which the request has been sent,
where value is the realm name.
A realm is used to group resources under a common 'place', and is used for
registered web applications
to have different or common sessions for a give user."))

(defmethod request-realm ((req hunchentoot::request))
  (aux-request-value 'realm req))

(defmethod (setf request-realm) (value (req hunchentoot::request))
  (setf (aux-request-value req) value))

(defclass session ()
  ((session-id :initform (get-next-session-id)
               :reader session-id
               :type integer
               :documentation "The unique ID \(an INTEGER) of the session.")
   (session-realm :initform (request-realm *request*)
          :reader session-realm
          :documentation "Defines a realm for this session.
A realm is injected by *request* aux parameter, and is used to group
resources that will share this session object.")
   (session-string :reader session-string
                   :documentation "The session strings encodes enough
data to safely retrieve this session. It is sent to the browser as a
cookie value or as a GET parameter.")
   (user-agent :initform (user-agent *request*)
               :reader session-user-agent
               :documentation "The incoming 'User-Agent' header that
was sent when this session was created.")
   (remote-addr :initform (real-remote-addr *request*)
              :reader session-remote-addr
              :documentation "The remote IP address of the client when
this sessions was started as returned by REAL-REMOTE-ADDR.")
   (session-start :initform (get-universal-time)
                  :reader session-start
                  :documentation "The time this session was started.")
   (last-click :initform (get-universal-time)
               :reader session-last-click
               :documentation "The last time this session was used.")
   (session-data :initarg :session-data
                 :initform nil
                 :reader session-data
                 :documentation "Data associated with this session -
see SESSION-VALUE.")
   (session-counter :initform 0
                    :reader session-counter
                    :documentation "The number of times this session
has been used.")
   (max-time :initarg :max-time
             :initform *session-max-time*
             :accessor session-max-time
             :type fixnum
             :documentation "The time \(in seconds) after which this
session expires if it's not used."))
  (:documentation "SESSION objects are automatically maintained
by Hunchentoot. They should not be created explicitly with
MAKE-INSTANCE but implicitly with START-SESSION. Note that
SESSION objects can only be created when the special variable
*REQUEST* is bound to a REQUEST object."))

(defun encode-session-string (id user-agent remote-addr start realm)
  "Create a uniquely encoded session string based on the values ID,
USER-AGENT, REMOTE-ADDR, and START"
  ;; *SESSION-SECRET* is used twice due to known theoretical
  ;; vulnerabilities of MD5 encoding
  (md5-hex (concatenate 'string
            *session-secret*
            (md5-hex (format nil "~A~A~@[~A~]~@[~A~]~A~@[~A~]"
                                         *session-secret*
                                         id
                                         (and *use-user-agent-for-sessions*
                                              user-agent)
                                         (and *use-remote-addr-for-sessions*
                                              remote-addr)
                                         start
                     realm)))))

(defun stringify-session (session)
  "Creates a string representing the SESSION object SESSION. See
ENCODE-SESSION-STRING."
  (encode-session-string (session-id session)
                         (session-user-agent session)
                         (session-remote-addr session)
                         (session-start session)
             (session-realm session))



(defun session-verify (request)
  "Tries to get a session identifier from the cookies \(or
alternatively from the GET parameters) sent by the client. This
identifier is then checked for validity against the REQUEST object
REQUEST. On success the corresponding session object \(if not too old)
is returned \(and updated). Otherwise NIL is returned."
  (let ((session-identifier (or (cookie-in *session-cookie-name* request)
                                (get-parameter *session-cookie-name*
request))))
    (unless (and session-identifier
                 (stringp session-identifier)
                 (plusp (length session-identifier)))
      (return-from session-verify nil))
    (destructuring-bind (id-string session-string)
        (split ":" session-identifier :limit 2)
      (let* ((id (and (scan "^\\d+$" id-string)
                      (parse-integer id-string
                                     :junk-allowed t)))
             (session (and id
                           (get-stored-session id)))
             (user-agent (user-agent request))
             (remote-addr (remote-addr request)))
        (unless (and session
                     session-string
                     (string= session-string
                              (session-string session))
                     (string= session-string
                              (encode-session-string id
                                                     user-agent
                                                     (real-remote-addr
request)
                                                     (session-start session)
                             (request-realm request))))
          (when *reply*
            (cond ((null session)
                    (log-message :notice "No session for session identifier
'~A' (User-Agent: '~A', IP: '~A')"
                                 session-identifier user-agent remote-addr))
                  (t
                    (log-message :warning "Fake session identifier '~A'
(User-Agent: '~A', IP: '~A')"
                                 session-identifier user-agent
remote-addr))))
          (when session
            (remove-session session))
          (return-from session-verify nil))
        (incf (slot-value session 'session-counter))
        (setf (slot-value session 'last-click) (get-universal-time))
        session))))

(defun start-session (&optional (path "/"))
  "Returns the current SESSION object. If there is no current session,
creates one and updates the corresponding data structures. In this
case the function will also send a session cookie to the browser.
This function slightly differs from standard hunchentoot implementation
because
it can bound a session to a specific url inside the same server instance."
  (count-session-usage)
  (let ((session (session *request*)))
    (when session
      (return-from start-session session))
    (setf session (make-instance 'session)
          (session *request*) session)
    (with-lock (*session-data-lock*)
      (setq *session-data* (acons (session-id session) session
*session-data*)))
    (set-cookie *session-cookie-name*
                :value (session-cookie-value session)
                :path path)
    (setq *session* session)))

On Jan 7, 2008 7:43 AM, Andrea Chiumenti <kiuma72 at gmail.com> wrote:

> Hello, Edi
>
> I've spent the weekend on figuring out how to bind sessions for each
> application registered and finally I've found a solution!
> Before writing function redefinitions into my project, thing that I find a
> bit 'dirty', do you want me to post here my modifications so
> that sessions have their own realm and session cookies are bound to
> specific applications ?
>
> Cheers,
> kiuma
>
>
> On Jan 7, 2008 5:45 AM, Edi Weitz < edi at agharta.de> wrote:
>
> > On Sat, 5 Jan 2008 11:31:06 +0100, "Andrea Chiumenti" <
> > kiuma72 at gmail.com> wrote:
> >
> > > now my question is *session-data* common to all hunchentoot servers
> > > instantiated on the same lisp instance ?
> >
> > Yes, it's a global special variable.
> >
> > > Another question, now suppose we have in a single hunchentoot server
> > > serves two applications ( distinguished by their path ).  It seems
> > > that hunchentoot shares the session between these two, and sometime
> > > it's good, but what should I do if I want applications to share
> > > different sessions ?
> >
> > There's currently no mechanism for this.  Unless you write your own,
> > of course.
> > _______________________________________________
> > tbnl-devel site list
> > tbnl-devel at common-lisp.net
> > http://common-lisp.net/mailman/listinfo/tbnl-devel
> >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/tbnl-devel/attachments/20080108/f7d2ec97/attachment.html>


More information about the Tbnl-devel mailing list