I'm using the ring basic-authentication library available for compojure. The authenticated? function takes a username and a password in order to authenticate, but in my particular case I need to access other parameters passed in by the user request besides a username and a password.
For instance, consider a case where there are multiple servers, and a user has an account on a particular server. That user would therefore need to authenticate with (log-on to) a particular server. Therefore I need his username, password, AND server to do the authentication.
Handling a "normal" case which just calls for a username and password might look something like this (using example sql to hit a database):
; curl my_id:my_pass@localhost/my_request
(defn authenticated? [id password]
(first (select user (where {:id id :password password}) (limit 1))))
I'd like to do something like this:
; curl my_id:my_pass@localhost/my_server/my_request
(defn authenticated? [id password ??server??]
(first (select user (where {:server server :id id :password password}) (limit 1))))
I guess my question is, how do I access all request params from inside authenticated? Or, alternatively, how do I pass the server id into the authenticated? function?
Thanks.
In accordance with the comments to the question above, the approach would look like this (just a sketch, I haven't tested whether this works due to lack of a running setup with ring):
(defn wrap-basic-auth-server [handler authfn]
(fn [request]
(-> request
(wrap-basic-authentication (partial authfn (get-in request [:params :server])))
handler)))
What's happening here is that the code is assuming that your server url param will have been added by wrap-params
(from ring.middleware.params) to the request map. wrap-basic-authentication
is called then with the handler (typical ring middleware, i.e. any other wrapper / handler coming afterwards) and a new (partial) function, which is just your authenticate function which has already swallowed the server arg.
And then instead of just calling wrap-basic-authentication
in your routes, you need to add wrap-params
and wrap-basic-auth-server
and you need your new auth function. E.g.
(defn authenticated? [server user pass]
... your code ...)
(def app
(-> app-routes
... potential other wrappers elided ...
(wrap-params)
(wrap-basic-auth-server authenticated?)))
As I said, I've not tested this code, but it should get you started.