ring

Eugen 2024-06-15T02:42:23.828169Z

hi, How can I invalidate a ring session ? I'm working to integrate pac4j with ring and I've gotten quite far. One situation that I don't know to handle is session invalidate to implement renew-session. Basically copy the session to a new session ID. There is no support for this OOTB with ring-session middleware. I also miss a function to get the current session id from a request. I guess a var could be used to store the key name for the session. I could probably implement this once I figure things out, but it's a recurring pattern that IMO should exist as part of the library / docs. If I'm not the only one that thinks like this I will open an issue and maybe we can get the functionality implemented.

2024-06-15T02:57:10.027449Z

Dunno if it is documented, but if add a :recreate key to the session middleware with a truthy value it will delete and create a new session

2024-06-15T02:57:51.893809Z

The key name for the session is added here https://github.com/ring-clojure/ring/blob/master/ring-core/src/ring/middleware/session.clj#L31

Eugen 2024-06-15T03:03:45.327729Z

thank you

weavejester 2024-06-17T10:59:17.911379Z

It's documented in the wiki (https://github.com/ring-clojure/ring/wiki/Sessions) but should also probably be in the docstring of wrap-session.

Eugen 2024-06-17T11:12:56.218619Z

thank you. If I ever get some free time I would like to improve the docs. Clojure tools / libs generally lack begginner friendly documentation IMO 😞

Eugen 2024-06-17T11:15:03.513989Z

during my work integrating pac4j (ongoing) I also think an alternative session implementation where the store is passes out of band and not via request / response maps might be ok as well. pac4j expects a mutable session store (because of Servlet API) and I have to work around that .

Eugen 2024-06-17T11:15:49.746099Z

having just the session ID on req / response and passing the store out of band to the handlers might be a solution

weavejester 2024-06-17T11:17:40.191769Z

Some sessions are updated via the HTTP response (e.g. serialized session data in encrypted cookies), rather than via some side-channel (such as a database). Ring targets the lowest common denominator.

weavejester 2024-06-17T11:21:22.886599Z

However, you can always add middleware to supply a mutable session, e.g.

(defn wrap-mutable-session [handler]
  (fn [request]
    (let [session  (atom (:session request))
          request  (assoc request :mutable-session session)
          response (handler request)]
      (assoc response :session @session))))

Eugen 2024-06-17T11:28:15.801099Z

yes, that is true, but the issue I find is that the ecosystem around this is missing in Clojure /ring . take for example ring-session-timeout - it expects the session to be under :session key so it will update that and you get into a divergent sitution https://github.com/ring-clojure/ring-session-timeout/blob/2cf787cb05caebe66c3af5201aaf0c517601f03e/src/ring/middleware/session_timeout.clj#L40 . IMO it would be nice if the session protocol was more extensive and hid the session details from the user. e.g. get-session-id [req] for example could hide the session key from user / implementors. get-session [req] could do the same ?! I can only come up with mutable API's - sorry . My point is, having session under :session - is an implementation detail that should be hidden from users. This can free middleware implementors to store session how they want.

weavejester 2024-06-17T11:35:33.657049Z

The wrap-mutable-session example above will work with ring-session-timeout, as long as ring-session-timeout wraps it.

weavejester 2024-06-17T11:35:59.304969Z

Can you tell me a little more about what you're trying to do, and why you need a mutable session store?

Eugen 2024-06-17T11:36:41.076269Z

sure. I can tell you why I THINK I need it - I don't know if I really do 🙂

Eugen 2024-06-17T11:39:06.821439Z

I have this WIP ring pac4j implementation that I am working on https://github.com/netdava/snm/blob/main/dev/ring_pac4j.clj .

Eugen 2024-06-17T11:39:28.899729Z

pac4j seesm to have a lot of available Auth Clients

Eugen 2024-06-17T11:39:47.424799Z

I have auth working - code is rough, mind your step

Eugen 2024-06-17T11:41:00.413849Z

I don't have role assignement to user - so you can't access the /protected link - but you do get rejected proeprly

weavejester 2024-06-17T11:43:24.159779Z

If I'm understanding correctly, pac4j is some sort of security framework, and to interface with it you need Java objects for sessions, cookies, etc.

Eugen 2024-06-17T11:47:09.795249Z

yes, in a nutshell

Eugen 2024-06-17T11:48:00.496809Z

in this case, having both :session and the external session store is more work than having just the external session store

Eugen 2024-06-17T11:49:31.665569Z

the :session approach has merit with regards to external (redis) session stores - in the sense that local session is local until the response is sent and then it gets written to the external store

weavejester 2024-06-17T11:49:48.826279Z

Is the pac4j session store required only for the lifespan of the handler? Or to put it another way, can it be updated after the response is returned?

Eugen 2024-06-17T11:52:01.607509Z

I will have to think about that. I think so. Right now I keep a request + response as atoms and update those and then merge back in the response once it's done. But I just started with this so not sure if it will work with all cases. https://github.com/netdava/snm/blob/a6d257697516336a88cedb38ccd7f05abe813da5/dev/ring_pac4j.clj#L245

weavejester 2024-06-17T12:06:31.887609Z

I don't know anything about pac4j, but can't you do something like:

(defn wrap-pac4j [handler options]
  (fn [request]
    (let [config  (make-pac4j-config options)]
          context (make-pac4j-context request)]
      (do-side-effectful-pac4j-stuff config context)
      (let [response (handler request)]
        (merge-pac4j-response response config context)))))
And have the various pac4j objects, such as the context and session store, have local mutable state that can be read by merge-pac4j-response . The idea is that you'd get the relevant information from the request map, convert it into a form pac4j can read, and set up mutable stores to hold what pac4j wants to write. Then when pac4j is done, you can read that mutable data, and convert it back into something you can place on the response map.

Eugen 2024-06-17T12:12:22.428479Z

thanks

Eugen 2024-06-17T12:12:52.941569Z

I'll see what I can do and hopefully I will get it working and ask for some feedback to publish it

weavejester 2024-06-17T12:13:03.698809Z

Good luck!

Eugen 2024-06-17T12:13:07.909539Z

thanks