tags:

views:

258

answers:

2

I have not seen a really good example on the web. How can I add authentication to a request like this:

(defun login-show-posts ()
  (interactive)
  (let ((url-request-method "GET")
        (url-request-extra-headers '(("Content-Type" . "application/xml"))))
    (url-retrieve "http://localhost:3000/essay/1.xml" 
    (lambda (status)
                    (switch-to-buffer (current-buffer))
                    ))))

if for example, the user and pass is admin:admin?

+1  A: 

I got the impression that url.el was designed mostly for interactive operations, i.e. you do a call without authorisation, the server responds with a 403 "authorization needed" (correct code?) status and url.el will query the user for user name and password.

You can have a look at my code on http://github.com/hdurer/fluiddb.el where I try to do things programmatically.

Basically, I create the HTTP authorzation header myself (base64 encoding the correctly formatted string and adding the correct header to url-request-extra-headers). Then in a second step I need to add advice to url-http-handle-authentication so that it won't ask the user should the passed credentials not be acceptable.

This feels a lot like raping url.el but it works for me and is the only way I could make it work.


Your code would thus look something like this:

 (defvar xyz-user-name "admin")
 (defvar xyz-password "admin")

 (defvar xyz-block-authorisation nil 
   "Flag whether to block url.el's usual interactive authorisation procedure")

 (defadvice url-http-handle-authentication (around xyz-fix)
   (unless xyz-block-authorisation
       ad-do-it))
 (ad-activate 'url-http-handle-authentication)


 (defun login-show-posts ()
   (interactive)
   (let ((xyz-block-authorisation t)
         (url-request-method "GET")
         (url-request-extra-headers 
          `(("Content-Type" . "application/xml")
            ("Authorization" . ,(concat "Basic "
                                        (base64-encode-string
                                         (concat xyz-user-name ":" xyz-password)))))))
     (url-retrieve "http://localhost:3000/essay/1.xml" 
                   (lambda (status)
                     (switch-to-buffer (current-buffer))
                     ))))
HD
Thanks for your comment. I have reading the sources from twit.el, twitter.el and mediawiki.el, but I have not been able to dissect what is it exactly that they are doing for authentication. I'll check yours as well. Thanks again!
wallyqs
A quite different solution might be to not use url.el -- I just had a look at the identica mode (just google for it) and there the HTTP request is assembled fully manually. To me that feels a bit like reinventing the wheel though.
HD
The twiter mode I use (twit.el) doesn't do authentication programatically but relies on url.el -- i.e the user gets asked on the first request for twitter name and password.
HD
Thank you very much for sharing the code! This is exactly what I needed. I'll be looking at your fluiddb.el to learn more!
wallyqs
+1  A: 

With twit.el, there was a little farting around to make it work. Authentication info is stored inside of an alist. This a list is bound to the symbol in the variable url-basic-auth-storage.

ELISP> (require 'url)
ELISP> (pp url-basic-auth-storage)
url-http-real-basic-auth-storage

ELISP> (pp (symbol-value url-basic-auth-storage))
(("twitter.com:443"  ("Twitter API" . "@uTh5tr!n6==")) 
 ("twitter.com:80"  ("Twitter API" . "AnotherAuthString==")))
ELISP> 

You could probably do something like this:

(let ((my-temporary-auth '(("host.com:80" ("Auth Realm" . "@uTH5r!n6==")))))
      (url-basic-auth-storage 'my-temporary-auth))
   (do-gunk))

This will leave the users authentication info alone (if they have any). Upon retrospect that might have been the smarter way to go with twit.el.

Jonathan Arkell
However, with that you'll still need the defadvice hack unless you want url.rl to possibly ask the user for alternative auth details right? (Meaning if the service still returns a 403 despite the authorization header sent.)
HD
You shouldn't need the defadvice hack. If I recall, url-http-handle-authentication uses url-http-basic-authorization as an auth cache, so if there is an entry already in the alist, it won't prompt the user, unless it gets a 2nd 403 header.
Jonathan Arkell
Thanks Jonathan for your answer (and for twit.el), I currently went for HD's approach though I've found twit.el source useful as well to learn more about how to use url.el.
wallyqs
Nice solution. Just for the dumb people out there, like myself, don't forget to (require 'url).Although twit.el has it, if you are coding yourself it's possible to forget about it.
didi