;;; url-http-ntlm.el --- NTLM authentication for the url library
-;; Copyright (C) 2008 Tom Schutzer-Weissmann
+;; Copyright (C) 2008, 2015 Free Software Foundation, Inc.
-;; Author: Tom Schutzer-Weissmann <tom@schutzer-weissmann.net>
+;; Author: Tom Schutzer-Weissmann <tom.weissmann@gmail.com>
+;; Maintainer: Thomas Fitzsimmons <fitzsim@fitzsim.org>
;; Keywords: comm, data, processes, hypermedia
;; This program is free software; you can redistribute it and/or modify
;;
;; Installation:
;;
-;; Add the directory containing this file to the load path and then
-;; load the url-http-ntlm package. One way would be to add something
-;; like the lines below to your .emacs file:
-;;
-;; (add-to-list 'load-path ".emacs.d/url-http-ntlm")
-;; (require 'url-http-ntlm)
+;; M-x package-install RET url-http-ntlm RET
;;
;; Acknowledgements:
;;
(require 'cl)
(require 'ntlm)
-(defvar url-http-ntlm-auth-storage nil
+\f
+;;; Private variables.
+(defvar url-http-ntlm--auth-storage nil
"Authentication storage.
An alist that maps a server name to a pair of \(<username> <ntlm
hashes>\).
Note that for any server, only one user and password is ever stored.")
-(defun url-ntlm-auth (url &optional prompt overwrite realm args)
- "Return an NTLM HTTP authorization header.
-Get the contents of the Authorization header for a HTTP response
-using NTLM authentication, to access URL. Because NTLM is a
-two-step process, this function expects to be called twice, first
-to generate the NTLM type 1 message (request), then to respond to
-the server's type 2 message (challenge) with a suitable response.
-
-PROMPT, OVERWRITE, and REALM are ignored.
-
-ARGS is expected to contain the WWW-Authentication header from
-the server's last response. These are used by
-`url-http-get-stage' to determine what stage we are at."
- (url-ntlm-ensure-keepalive)
- (let ((stage (url-ntlm-get-stage args)))
- (case stage
- ;; NTLM Type 1 message: the request
- (:request
- (destructuring-bind (&optional server user hash)
- (url-http-ntlm-authorisation url)
- (when server
- (url-http-ntlm-string
- (ntlm-build-auth-request user server)))))
- ;; NTLM Type 3 message: the response
- (:response
- (let ((challenge (url-http-ntlm-get-challenge)))
- (destructuring-bind (server user hash)
- (url-http-ntlm-authorisation url)
- (url-http-ntlm-string
- (ntlm-build-auth-response challenge
- user
- hash)))))
- (:error
- (url-http-ntlm-authorisation url :clear)))))
+(defvar url-http-ntlm--last-args nil
+ "Stores the last `url-http-ntlm--get-stage' arguments and return value.
+This is used to detect multiple calls.")
+(make-variable-buffer-local 'url-http-ntlm--last-args)
-(defun url-ntlm-ensure-keepalive ()
+\f
+;;; Private functions.
+(defun url-http-ntlm--ensure-keepalive ()
"Report an error if `url-http-attempt-keepalives' is not set."
(assert url-http-attempt-keepalives
nil
(concat "NTLM authentication won't work unless"
" `url-http-attempt-keepalives' is set!")))
-(defun url-ntlm-clean-headers ()
+(defun url-http-ntlm--clean-headers ()
"Remove Authorization element from `url-http-extra-headers' alist."
(setq url-http-extra-headers
- (url-http-ntlm-rmssoc "Authorization" url-http-extra-headers)))
+ (url-http-ntlm--rmssoc "Authorization" url-http-extra-headers)))
-(defvar url-ntlm-last-args nil
- "Stores the last ARGS argument to `url-ntlm-get-stage' and the return value.
-This is used to detect multiple calls.")
-(make-variable-buffer-local 'url-ntlm-last-args)
-
-(defun url-ntlm-get-stage (args)
+(defun url-http-ntlm--get-stage (args)
"Determine what stage of the NTLM handshake we are at.
PROMPT and ARGS come from `url-ntlm-auth''s caller,
`url-get-authentication'. Their meaning depends on the current
(auth-header (assoc "Authorization" url-http-extra-headers))
(case-fold-search t)
stage)
- (if (eq args (car url-ntlm-last-args))
+ (if (eq args (car url-http-ntlm--last-args))
;; multiple calls, return the same argument we returned last time
- (cdr url-ntlm-last-args)
+ (cdr url-http-ntlm--last-args)
(let ((stage
(cond ((and auth-header (string-match response-rxp
(cdr auth-header)))
:response)
(t
:request))))
- (url-ntlm-clean-headers)
- (setq url-ntlm-last-args (cons args stage))
+ (url-http-ntlm--clean-headers)
+ (setq url-http-ntlm--last-args (cons args stage))
stage))))
-(defun url-http-ntlm-authorisation (url &optional clear)
+(defun url-http-ntlm--authorisation (url &optional clear)
"Get or clear NTLM authentication details for URL.
If CLEAR is non-nil, clear any saved credentials for server.
Otherwise, return the credentials, prompting the user if
(server (url-host href))
(user (url-user href))
(pass (url-password href))
- (stored (assoc server url-http-ntlm-auth-storage))
+ (stored (assoc server url-http-ntlm--auth-storage))
(both (and user pass)))
(if clear
;; clear
(unless both
- (setq url-http-ntlm-auth-storage
- (url-http-ntlm-rmssoc server url-http-ntlm-auth-storage))
+ (setq url-http-ntlm--auth-storage
+ (url-http-ntlm--rmssoc server url-http-ntlm--auth-storage))
nil)
;; get
(if (or both
(entry `(,server . (,user*
,(ntlm-get-password-hashes pass*)))))
(unless both
- (setq url-http-ntlm-auth-storage
+ (setq url-http-ntlm--auth-storage
(cons entry
- (url-http-ntlm-rmssoc server
- url-http-ntlm-auth-storage))))
+ (url-http-ntlm--rmssoc server
+ url-http-ntlm--auth-storage))))
entry)
stored))))
-(defun url-http-ntlm-get-challenge ()
+(defun url-http-ntlm--get-challenge ()
"Return the NTLM Type-2 message in the WWW-Authenticate header, if present."
(save-restriction
(mail-narrow-to-head)
www-authenticate)
(base64-decode-string (match-string 1 www-authenticate))))))
-(defun url-http-ntlm-rmssoc (key alist)
+(defun url-http-ntlm--rmssoc (key alist)
"Remove all elements whose `car' match KEY from ALIST."
(remove* key alist :key 'car :test 'equal))
-(defun url-http-ntlm-string (data)
+(defun url-http-ntlm--string (data)
"Return DATA encoded as an NTLM string."
(concat "NTLM " (base64-encode-string data :nobreak)))
+\f
+;;; Public function called by `url-get-authentication'.
+(defun url-ntlm-auth (url &optional prompt overwrite realm args)
+ "Return an NTLM HTTP authorization header.
+Get the contents of the Authorization header for a HTTP response
+using NTLM authentication, to access URL. Because NTLM is a
+two-step process, this function expects to be called twice, first
+to generate the NTLM type 1 message (request), then to respond to
+the server's type 2 message (challenge) with a suitable response.
+
+PROMPT, OVERWRITE, and REALM are ignored.
+
+ARGS is expected to contain the WWW-Authentication header from
+the server's last response. These are used by
+`url-http-get-stage' to determine what stage we are at."
+ (url-http-ntlm--ensure-keepalive)
+ (let ((stage (url-http-ntlm--get-stage args)))
+ (case stage
+ ;; NTLM Type 1 message: the request
+ (:request
+ (destructuring-bind (&optional server user hash)
+ (url-http-ntlm--authorisation url)
+ (when server
+ (url-http-ntlm--string
+ (ntlm-build-auth-request user server)))))
+ ;; NTLM Type 3 message: the response
+ (:response
+ (let ((challenge (url-http-ntlm--get-challenge)))
+ (destructuring-bind (server user hash)
+ (url-http-ntlm--authorisation url)
+ (url-http-ntlm--string
+ (ntlm-build-auth-response challenge
+ user
+ hash)))))
+ (:error
+ (url-http-ntlm--authorisation url :clear)))))
+
+\f
+;;; Register `url-ntlm-auth' HTTP authentication method.
(url-register-auth-scheme "ntlm" nil 8)
(provide 'url-http-ntlm)