Hi all,
First I'd like to say that TBNL looks really nice, and replaces much of what I have been trying to do lately on my own.
I have a question regarding authorization; The goal of having authorization is to provide restricted access to a set of pages. The example in test.lisp on gives access to one page, which is the one generated by the authorization-page function itself.
How would I go about using authroization to restrict access to a set of pages, perhaps even including static ones? Should I set it up so that a prefix of the URIs of that set always leads to a handler which calls authorization? In that case, how would such a handler look like?
Thanks,
Björn
On 10 Aug 2004 14:27:28 +0200, d95-bli@nada.kth.se (Björn Lindberg) wrote:
First I'd like to say that TBNL looks really nice, and replaces much of what I have been trying to do lately on my own.
Thanks.
I have a question regarding authorization; The goal of having authorization is to provide restricted access to a set of pages. The example in test.lisp on gives access to one page, which is the one generated by the authorization-page function itself.
How would I go about using authroization to restrict access to a set of pages, perhaps even including static ones? Should I set it up so that a prefix of the URIs of that set always leads to a handler which calls authorization? In that case, how would such a handler look like?
TBNL currently doesn't have code to automate that. You can, of course, use Apache's facilities and ignore TBNL. Or you might want to do something like this (untested)
(defmacro with-authorization ((authorizer) &body body) (with-unique-names (user password) `(multiple-value-bind (,user ,password) (authorization) (cond ((funcall ,authorizer ,user ,password) ,@body) (t (require-authorization))))))
(defun my-authorizer (user password) (and (string= user "foo") (string= password "bar")))
and then
(defun page () (with-authorization (#'my-authorizer) (with-html (:html (:head (:title "Blabla")) (:body "More bla")))))
Another option would be to let the first dispatcher in the list of dispatchers do the following:
1. If URL doesn't need authorization just return NIL so the next dispatcher has its turn.
2. If URL needs authorization and user is authorized also return NIL.
3. Otherwise dispatch to a fixed handler which just calls REQUIRE-AUTHORIZATION.
Does that help?
Cheers, Edi.
Edi Weitz edi@agharta.de writes:
I have a question regarding authorization; The goal of having authorization is to provide restricted access to a set of pages. The example in test.lisp on gives access to one page, which is the one generated by the authorization-page function itself.
How would I go about using authroization to restrict access to a set of pages, perhaps even including static ones? Should I set it up so that a prefix of the URIs of that set always leads to a handler which calls authorization? In that case, how would such a handler look like?
TBNL currently doesn't have code to automate that. You can, of course, use Apache's facilities and ignore TBNL. Or you might want to do something like this (untested)
(defmacro with-authorization ((authorizer) &body body) (with-unique-names (user password) `(multiple-value-bind (,user ,password) (authorization) (cond ((funcall ,authorizer ,user ,password) ,@body) (t (require-authorization))))))
(defun my-authorizer (user password) (and (string= user "foo") (string= password "bar")))
and then
(defun page () (with-authorization (#'my-authorizer) (with-html (:html (:head (:title "Blabla")) (:body "More bla")))))
Another option would be to let the first dispatcher in the list of dispatchers do the following:
If URL doesn't need authorization just return NIL so the next dispatcher has its turn.
If URL needs authorization and user is authorized also return NIL.
Otherwise dispatch to a fixed handler which just calls REQUIRE-AUTHORIZATION.
Does that help?
Yes, I believe so. I think my insufficient understanding of the underlying HTTP mechanism led me to believe it was more complicated than it apparently is.
Am I correct now to believe that it is in reality Apache which takes care of the authorization, so that once a user gave a proper username and password, he will be authorized for the rest of his session? So all that needs to be done is for each and every handler of access restricted pages to call tbnl:authorization and check for valid username and passwords?
If the above is correct, then any misconceptions has been cleared up on my part. Both you and Stefan gave me some good suggestions for what to try. I suspect that the with-authorization macro is the simplest solution if the number of access restricted pages are small, which they are in my case, so maybe I will go with that. I'll experiment with it tonight.
Björn
On 10 Aug 2004 16:49:24 +0200, d95-bli@nada.kth.se (Björn Lindberg) wrote:
Am I correct now to believe that it is in reality Apache which takes care of the authorization, so that once a user gave a proper username and password, he will be authorized for the rest of his session?
No. The HTTP protocol has no concept of a "session" at all - each request/reply pair is treated in isolation.
Basic authentication works like this:
0. Client sends a request.
1. The server somehow checks whether the client (the browser) has sent the proper username and password. (These are encoded in a header the client sends.)
How this is checked can be implemented in different ways. You can ask Apache to handle this but in the examples just given (macro, dispatcher, and so on) Apache was not involved but rather TBNL did the checking.
2. If username and password are OK the server sends the requested contents.
3. If they're not OK the server sends back a 401 (Unauthorized) return code. It will also usually send back a "WWW-Authenticate" header which reveals a "Realm" to the client. This action /might/ result in a box popping up in your browser asking you to enter the credentials.
This process can be repeated as often as needed. Note that no knowledge of what happended in the past (no "session") is required for this.
So all that needs to be done is for each and every handler of access restricted pages to call tbnl:authorization and check for valid username and passwords?
Yes.
Edi Weitz edi@agharta.de writes:
On 10 Aug 2004 16:49:24 +0200, d95-bli@nada.kth.se (Björn Lindberg) wrote:
Am I correct now to believe that it is in reality Apache which takes care of the authorization, so that once a user gave a proper username and password, he will be authorized for the rest of his session?
No. The HTTP protocol has no concept of a "session" at all - each request/reply pair is treated in isolation.
Basic authentication works like this:
Client sends a request.
The server somehow checks whether the client (the browser) has sent the proper username and password. (These are encoded in a header the client sends.)
How this is checked can be implemented in different ways. You can ask Apache to handle this but in the examples just given (macro, dispatcher, and so on) Apache was not involved but rather TBNL did the checking.
If username and password are OK the server sends the requested contents.
If they're not OK the server sends back a 401 (Unauthorized) return code. It will also usually send back a "WWW-Authenticate" header which reveals a "Realm" to the client. This action /might/ result in a box popping up in your browser asking you to enter the credentials.
This process can be repeated as often as needed. Note that no knowledge of what happended in the past (no "session") is required for this.
I see. the reason I thought it was handled by HTTP was because, as you imply, the window requesting username and password usually only pops up once. If there nowhere in the chain was any caching of the two, or 'state', then the access window would pop up for each and every access restricted page.
Now you've led me to believe that it is actually the client's browser that is storing the authentification information and resending it upon request from the server. Is this right? (Sorry for bothering you with this elementia.)
So all that needs to be done is for each and every handler of access restricted pages to call tbnl:authorization and check for valid username and passwords?
Yes.
Well, that is comforting at least. :-)
Björn
On 10 Aug 2004 17:29:28 +0200, d95-bli@nada.kth.se (Björn Lindberg) wrote:
I see. the reason I thought it was handled by HTTP was because, as you imply, the window requesting username and password usually only pops up once. If there nowhere in the chain was any caching of the two, or 'state', then the access window would pop up for each and every access restricted page.
Now you've led me to believe that it is actually the client's browser that is storing the authentification information and resending it upon request from the server. Is this right? (Sorry for bothering you with this elementia.)
Yes, it's the browser which (re-)sends the credentials automatically. Actually, it should try each request without credentials first because the server doesn't provide any information as to which other pages need authorization (and even if the same page will still require authorization tomorrow or in ten seconds).
However, that would involve two requests per each page and the browser would get very many 401 replies. Therefore, all current browser will volunteer to send credentials based on certain heuristics (like if it's the same server and the same directory or somesuch).
Cheers, Edi.
On 2004-08-10 14:27:28, Björn Lindberg wrote:
How would I go about using authroization to restrict access to a set of pages, perhaps even including static ones? Should I set it up so that a prefix of the URIs of that set always leads to a handler which calls authorization? In that case, how would such a handler look like?
You could write a wrapper function for the handler. Or a function which generates wrapper functions for the handler, according for the specific authorization needs.
Your own dispatcher (or one generated with CREATE-PREFIX-DISPATCHER or CREATE-REGEX-DISPATCHER) then just calls the wrapper. The wrapper handles the authorization and calls either REQUIRE-AUTHORIZATION or your original handler.
Something like this:
(create-prefix-dispatcher "/dealer/" (generate-auth-wrapper "dealer" #'dealer-handler))
If you really need to protect static files, too, then I'd suggest to write your own version of CREATE-STATIC-FILE-DISPATCHER-AND-HANDLER. Code is in html.lisp
[...] (when (equal (script-name request) uri) ;; the handler + (generate-auth-wrapper + auth-group (lambda () [...]
Regards, Stefan