| 5 | | __all__ = ['SecureSession', 'SecureSessionFilter'] |
|---|
| 6 | | |
|---|
| 7 | | class SecureSession(Component): |
|---|
| 8 | | implements(IRequestHandler) |
|---|
| 9 | | |
|---|
| 10 | | # IRequestHandler methods |
|---|
| 11 | | def match_request(self, req): |
|---|
| 12 | | # Never match anything by ourselves |
|---|
| 13 | | return False |
|---|
| 14 | | |
|---|
| 15 | | def process_request(self, req): |
|---|
| 16 | | orig_uri = req._reconstruct_url() |
|---|
| 17 | | self.log.debug('orig_uri: %s' % orig_uri) |
|---|
| 18 | | uri_parsed = urlparse(orig_uri) |
|---|
| 19 | | self.log.debug('uri_parsed: %s' % str(uri_parsed)) |
|---|
| 20 | | uri_port = uri_parsed[1].split(':') |
|---|
| 21 | | self.log.debug('uri_port: %s' % str(uri_port)) |
|---|
| 22 | | if len(uri_port) > 1: |
|---|
| 23 | | uri_port = uri_port[1] |
|---|
| 24 | | else: |
|---|
| 25 | | uri_port = None |
|---|
| 26 | | host = uri_parsed[1].split(':')[0] |
|---|
| 27 | | self.log.debug("host: %s" % str(host)) |
|---|
| 28 | | path = uri_parsed[2] |
|---|
| 29 | | self.log.debug("path: %s" % str(path)) |
|---|
| 30 | | parameters = uri_parsed[3] |
|---|
| 31 | | self.log.debug("parameters: %s" % str(parameters)) |
|---|
| 32 | | query = uri_parsed[4] |
|---|
| 33 | | self.log.debug("query: %s" % str(query)) |
|---|
| 34 | | fragment = uri_parsed[5] |
|---|
| 35 | | self.log.debug("fragment: %s" % str(fragment)) |
|---|
| 36 | | |
|---|
| 37 | | secport = self.config.get('secsession', 'secport', 443) |
|---|
| 38 | | if secport != 443: |
|---|
| 39 | | host = '%s:%s' % (host, str(secport)) |
|---|
| 40 | | elif uri_port: |
|---|
| 41 | | host = host.split(':')[0] |
|---|
| 42 | | |
|---|
| 43 | | uri = urlunparse(('https', host, path, parameters, query, fragment)) |
|---|
| 44 | | self.log.debug("Location: %s" % uri) |
|---|
| 45 | | req.send_response(302) |
|---|
| 46 | | req.send_header('Location', uri) |
|---|
| 47 | | req.end_headers() |
|---|
| 48 | | |
|---|
| | 5 | __all__ = ['SecureSessionFilter'] |
|---|
| 56 | | # We want to handle all sessions that use http:// and have an |
|---|
| 57 | | # authenticated user |
|---|
| 58 | | if req.scheme == 'http': |
|---|
| 59 | | match = req.authname != 'anonymous' |
|---|
| 60 | | handler = SecureSession(self.env) |
|---|
| 61 | | pass |
|---|
| | 11 | # self.log.info("setting up the match") ### 'twas too much noize |
|---|
| | 12 | |
|---|
| | 13 | # We provide a config hook for checking if the request is |
|---|
| | 14 | # secure. Simply checking the scheme is not the appropriate |
|---|
| | 15 | # choice in all case -- eg., if trac runs behind a proxy |
|---|
| | 16 | # server, then it will get simple http requests from the |
|---|
| | 17 | # proxy and we have to analyze headers to find out if |
|---|
| | 18 | # the original request was secure or not. |
|---|
| | 19 | # |
|---|
| | 20 | # Currently we can directly match a request attribute |
|---|
| | 21 | # as "@<attr> = <val>" or a http header line as "<hdlr> = <val>". |
|---|
| | 22 | # This could be generalized by, eg., taking a list of such |
|---|
| | 23 | # patterns, whatever. |
|---|
| | 24 | key, val = [ x.strip() for x in self.config.get('secsession', |
|---|
| | 25 | 'secpattern', |
|---|
| | 26 | '@scheme=https' |
|---|
| | 27 | ).split('=', 1) ] |
|---|
| | 28 | if key[0] == '@': |
|---|
| | 29 | myval = getattr(req, key[1:]) |
|---|
| | 30 | else: |
|---|
| | 31 | myval = req.get_header(key) |
|---|
| | 32 | |
|---|
| | 33 | if unicode(myval) != val: |
|---|
| | 34 | # Auth info is not available at the time of invoking filters, |
|---|
| | 35 | # so we can't yet make the decision about redirecting. |
|---|
| | 36 | # |
|---|
| | 37 | # Therefore we just wrap the handler into our redirection policy. |
|---|
| | 38 | # When the handler will be invoked, auth info will be there; |
|---|
| | 39 | # if auth is anon, our wrapper will call the original |
|---|
| | 40 | # handler, else it will perform the redirect. |
|---|
| | 41 | handler = SecureSessionWrapper(handler, self) |
|---|
| 65 | | return (template, content_type) |
|---|
| | 45 | return template, content_type |
|---|
| | 46 | |
|---|
| | 47 | |
|---|
| | 48 | class SecureSessionWrapper(object): |
|---|
| | 49 | |
|---|
| | 50 | def __init__(self, in_handler, filter): |
|---|
| | 51 | self.in_handler = in_handler |
|---|
| | 52 | self.config = filter.config |
|---|
| | 53 | self.log = in_handler.log |
|---|
| | 54 | |
|---|
| | 55 | def process_request(self, req): |
|---|
| | 56 | |
|---|
| | 57 | if not req.authname or req.authname == 'anonymous': |
|---|
| | 58 | return self.in_handler.process_request(req) |
|---|
| | 59 | |
|---|
| | 60 | self.log.info("redirect to secure site:") |
|---|
| | 61 | secport = self.config.getint('secsession', 'secport', 443) |
|---|
| | 62 | port = '' |
|---|
| | 63 | if secport != 443: |
|---|
| | 64 | port = ':%d' % secport |
|---|
| | 65 | |
|---|
| | 66 | req.redirect(''.join(['https://', |
|---|
| | 67 | req.server_name, |
|---|
| | 68 | port, |
|---|
| | 69 | req.href(), |
|---|
| | 70 | req.path_info |
|---|
| | 71 | ]) ) |
|---|
| | 72 | |
|---|