Tres Seaver
2017-12-20 a83610e170325e157726a4649923dff8ae303d12
commit | author | age
279d0f 1 from repoze.who._compat import CONTENT_TYPE
TS 2 from repoze.who._compat import REQUEST_METHOD
3 from repoze.who._compat import USER_AGENT
d85ba6 4
1d896c 5 from zope.interface import directlyProvides
cb5426 6 from repoze.who.interfaces import IRequestClassifier
CM 7 from repoze.who.interfaces import IChallengeDecider
d85ba6 8
c51195 9 _DAV_METHODS = (
CM 10     'OPTIONS',
11     'PROPFIND',
12     'PROPPATCH',
13     'MKCOL',
14     'LOCK',
15     'UNLOCK',
16     'TRACE',
17     'DELETE',
18     'COPY',
19     'MOVE'
20     )
d85ba6 21
c51195 22 _DAV_USERAGENTS = (
CM 23     'Microsoft Data Access Internet Publishing Provider',
24     'WebDrive',
25     'Zope External Editor',
26     'WebDAVFS',
27     'Goliath',
28     'neon',
29     'davlib',
30     'wsAPI',
31     'Microsoft-WebDAV'
32     )
d85ba6 33
c51195 34 def default_request_classifier(environ):
279d0f 35     """Return one of the following classifiers:
TS 36
37     'dav':  the request comes from a WebDAV agent.
38
39     'xmlpost':  the request is a POST of XML data.
40
41     'browser':  the request comes from a normal browser (default).
42     """
c51195 43     request_method = REQUEST_METHOD(environ)
CM 44     if request_method in _DAV_METHODS:
45         return 'dav'
46     useragent = USER_AGENT(environ)
47     if useragent:
48         for agent in _DAV_USERAGENTS:
49             if useragent.find(agent) != -1:
50                 return 'dav'
51     if request_method == 'POST':
6b7b34 52         if CONTENT_TYPE(environ).lower().startswith('text/xml'):
c51195 53             return 'xmlpost'
CM 54     return 'browser'
1d896c 55 directlyProvides(default_request_classifier, IRequestClassifier)
d85ba6 56
c51195 57 def default_challenge_decider(environ, status, headers):
79a95b 58     return status.startswith('401 ')
1d896c 59 directlyProvides(default_challenge_decider, IChallengeDecider)
0dd808 60
TS 61 def passthrough_challenge_decider(environ, status, headers):
62     """ Don't challenge for pre-challenged responses.
63
64     o Assume responsese with 'WWW-Authenticate' or an HTML content type
65       are pre-challenged.
66     """
67     if not status.startswith('401 '):
68         return False
69     h_dict = dict(headers)
70     if 'WWW-Authenticate' in h_dict:
71         return False
72     ct = h_dict.get('Content-Type')
73     if ct is not None:
74         return not ct.startswith('text/html')
75     return True
1d896c 76 directlyProvides(passthrough_challenge_decider, IChallengeDecider)