Пример #1
0
    def check_authentication(self):
        """Read and verify the front-end headers, update the user
        dict with information about the authorized user."""
        headers = lowerCmsHeaders(cherrypy.request.headers)
        user = cherrypy.request.user

        if 'cms-auth-status' not in headers:
            # Non SSL request
            raise cherrypy.HTTPError(403, "You are not allowed to access this resource.")

        if headers['cms-auth-status'] == 'NONE':
            # User authentication is optional
            return  # authn accepted

        # User information is available on headers
        prefix = suffix = ""
        hkeys = sorted(headers.keys())
        for hk in hkeys:
            hk = hk.lower()
            if hk[0:9] in ["cms-authn", "cms-authz"] and hk != "cms-authn-hmac":
                prefix += "h%xv%x" % (len(hk), len(headers[hk]))
                suffix += "%s%s" % (hk, headers[hk])
                hkname = hk.split('-', 2)[-1]
                if hk.startswith("cms-authn"):
                    user[hkname] = headers[hk]
                if hk.startswith("cms-authz"):
                    user['roles'][hkname] = {'site': set(), 'group': set()}
                    for r in headers[hk].split():
                        ste_or_grp, name = r.split(':')
                        user['roles'][hkname][ste_or_grp].add(name);

        vfy = hmac.new(self.key, prefix + "#" + suffix, hashlib.sha1).hexdigest()
        if vfy != headers["cms-authn-hmac"]:
            # HMAC does not match
            raise cherrypy.HTTPError(403, "You are not allowed to access this resource, hmac mismatch")
Пример #2
0
    def check_authentication(self):
        """Read and verify the front-end headers, update the user
        dict with information about the authorized user."""
        headers = lowerCmsHeaders(cherrypy.request.headers)
        user = get_user_info()

        if 'cms-auth-status' not in headers:
            # Non SSL request
            raise cherrypy.HTTPError(403, "You are not allowed to access this resource.")

        if headers['cms-auth-status'] == 'NONE':
            # User authentication is optional
            return  # authn accepted

        # User information is available on headers
        prefix = suffix = ""
        hkeys = sorted(headers.keys())
        for hk in hkeys:
            hk = hk.lower()
            if hk[0:9] in ["cms-authn", "cms-authz"] and hk != "cms-authn-hmac":
                prefix += "h%xv%x" % (len(hk), len(headers[hk]))
                suffix += "%s%s" % (hk, headers[hk])
                hkname = hk.split('-', 2)[-1]
                if hk.startswith("cms-authn"):
                    user[hkname] = headers[hk]
                if hk.startswith("cms-authz"):
                    user['roles'][hkname] = {'site': set(), 'group': set()}
                    for r in headers[hk].split():
                        ste_or_grp, name = r.split(':')
                        user['roles'][hkname][ste_or_grp].add(name)

        vfy = hmac.new(self.key, prefix + "#" + suffix, hashlib.sha1).hexdigest()
        if vfy != headers["cms-authn-hmac"]:
            # HMAC does not match
            raise cherrypy.HTTPError(403, "You are not allowed to access this resource, hmac mismatch")
Пример #3
0
def user_info_from_headers(key, verbose=False):
    """Read the user information HTTP request headers added by front-end.
    Validates the HMAC on them to check for tampering, and if all is ok,
    returns user info object with the data from the headers."""
    # Set initial user information for this request
    log = cherrypy.log
    headers = lowerCmsHeaders(cherrypy.request.headers)
    user = {
        'dn': None,
        'method': None,
        'login': None,
        'name': None,
        'roles': {}
    }

    # Reject if request was not authenticated.
    if 'cms-auth-status' not in headers:
        log("ERROR: authz denied, front-end headers not present")
        raise cherrypy.HTTPError(
            403, "You are not allowed to access this resource.")

    # If authentication is optional and wasn't done, accept.
    if headers['cms-auth-status'] == 'NONE':
        if verbose: log("DEBUG: authn optional and missing")
        return

    # Extract user information from the headers. Collect data required
    # for HMAC validation while processing headers.
    prefix = suffix = ""
    hkeys = sorted(headers.keys())
    for hk in hkeys:
        hk = hk.lower()
        if hk[0:9] in ("cms-authn", "cms-authz") and hk != "cms-authn-hmac":
            prefix += "h%xv%x" % (len(hk), len(headers[hk]))
            suffix += "%s%s" % (hk, headers[hk])
            hkname = hk.split('-', 2)[-1]
            if hk.startswith("cms-authn"):
                val = headers[hk]
                if hk in ("cms-authn-name", "cms-authn-dn"):
                    val = unicode(val, "utf-8")
                user[hkname] = val
            if hk.startswith("cms-authz"):
                user['roles'][hkname] = {'site': set(), 'group': set()}
                for r in headers[hk].split():
                    site_or_group, name = r.split(':')
                    user['roles'][hkname][site_or_group].add(name)

    # Check HMAC over authn/z headers with server key. If differs, reject.
    cksum = hmac.new(key, prefix + "#" + suffix, hashlib.sha1).hexdigest()
    if cksum != headers["cms-authn-hmac"]:
        log("ERROR: authz hmac mismatch, %s vs. %s" %
            (cksum, headers["cms-authn-hmac"]))
        raise cherrypy.HTTPError(
            403, "You are not allowed to access this resource.")

    # Authn/z is legal, accept
    if verbose:
        log("DEBUG: authn accepted for user %s" % user)
    return user
Пример #4
0
 def access(self):
     """
     Record a client access
     """
     request = cherrypy.request
     remote = request.remote
     response = cherrypy.response
     inheaders = lowerCmsHeaders(request.headers)
     outheaders = response.headers
     # identify size of body from HTTP Content-Length header
     rbytes = int(cherrypy.request.headers.get('Content-Length', 0))
     if not rbytes:
         try:
             # request.rfile.rfile.bytes_read is a custom CMS web
             #  cherrypy patch not always available, hence the test
             rbytes = (getattr(request.rfile, 'rfile', None)
                       and getattr(request.rfile.rfile, "bytes_read", None)
                       and request.rfile.rfile.bytes_read) or "-"
         except:
             try:
                 # this will work only when body is read from request
                 rbytes = cherrypy.request.body.fp.bytes_read
             except:
                 rbytes = "-"
     msg = ('%(t)s %(H)s %(h)s "%(r)s" %(s)s' +
            ' [data: %(i)s in %(b)s out %(T).0f us ]' +
            ' [auth: %(AS)s "%(AU)s" "%(AC)s" ]' +
            ' [ref: "%(f)s" "%(a)s" ]') % {
                't':
                self.time(),
                'H':
                self.host,
                'h':
                remote.name or remote.ip,
                'r':
                request.request_line,
                's':
                response.status,
                'i':
                rbytes,
                'b':
                outheaders.get('Content-Length', '') or "-",
                'T': (time.time() - request.start_time) * 1e6,
                'AS':
                inheaders.get("cms-auth-status", "-"),
                'AU':
                inheaders.get("cms-auth-cert",
                              inheaders.get("cms-auth-host", "")),
                'AC':
                getattr(request.cookie.get("cms-auth", None), "value", ""),
                'f':
                inheaders.get("Referer", ""),
                'a':
                inheaders.get("User-Agent", "")
            }
     self.access_log.log(logging.INFO, msg)
Пример #5
0
 def testLowerCmsHeaders(self):
     "Test lowerCmsHeaders function"
     val = 'cms-xx-yy'
     headers = {'CAPITAL': 1, 'Camel': 1, 'Cms-Xx-Yy': val, 'CMS-XX-YY': val, 'cms-xx-yy': val}
     lheaders = lowerCmsHeaders(headers)
     self.assertEqual(sorted(lheaders.keys()), sorted(['CAPITAL', 'Camel', val]))
     self.assertEqual(lheaders['CAPITAL'], 1)
     self.assertEqual(lheaders['Camel'], 1)
     self.assertEqual(lheaders[val], val)
     self.assertEqual(len(lheaders), 3)
Пример #6
0
 def testLowerCmsHeaders(self):
     "Test lowerCmsHeaders function"
     val = 'cms-xx-yy'
     headers = {'CAPITAL':1, 'Camel':1, 'Cms-Xx-Yy': val, 'CMS-XX-YY': val, 'cms-xx-yy': val}
     lheaders = lowerCmsHeaders(headers)
     self.assertEqual(sorted(lheaders.keys()), sorted(['CAPITAL', 'Camel', val]))
     self.assertEqual(lheaders['CAPITAL'], 1)
     self.assertEqual(lheaders['Camel'], 1)
     self.assertEqual(lheaders[val], val)
     self.assertEqual(len(lheaders.keys()), 3)
Пример #7
0
def user_info_from_headers(key, verbose=False):
    """Read the user information HTTP request headers added by front-end.
    Validates the HMAC on them to check for tampering, and if all is ok,
    returns user info object with the data from the headers."""
    # Set initial user information for this request
    log = cherrypy.log
    headers = lowerCmsHeaders(cherrypy.request.headers)
    user = {'dn': None, 'method': None, 'login': None, 'name': None, 'roles': {}}

    # Reject if request was not authenticated.
    if 'cms-auth-status' not in headers:
        log("ERROR: authz denied, front-end headers not present")
        raise cherrypy.HTTPError(403, "You are not allowed to access this resource.")

    # If authentication is optional and wasn't done, accept.
    if headers['cms-auth-status'] == 'NONE':
        if verbose: log("DEBUG: authn optional and missing")
        return

    # Extract user information from the headers. Collect data required
    # for HMAC validation while processing headers.
    prefix = suffix = ""
    hkeys = sorted(headers.keys())
    for hk in hkeys:
        hk = hk.lower()
        if hk[0:9] in ("cms-authn", "cms-authz") and hk != "cms-authn-hmac":
            prefix += "h%xv%x" % (len(hk), len(headers[hk]))
            suffix += "%s%s" % (hk, headers[hk])
            hkname = hk.split('-', 2)[-1]
            if hk.startswith("cms-authn"):
                val = headers[hk]
                if hk in ("cms-authn-name", "cms-authn-dn"):
                    val = unicode(val, "utf-8")
                user[hkname] = val
            if hk.startswith("cms-authz"):
                user['roles'][hkname] = {'site': set(), 'group': set()}
                for r in headers[hk].split():
                    site_or_group, name = r.split(':')
                    user['roles'][hkname][site_or_group].add(name)

    # Check HMAC over authn/z headers with server key. If differs, reject.
    cksum = hmac.new(key, prefix + "#" + suffix, hashlib.sha1).hexdigest()
    if cksum != headers["cms-authn-hmac"]:
        log("ERROR: authz hmac mismatch, %s vs. %s" % (cksum, headers["cms-authn-hmac"]))
        raise cherrypy.HTTPError(403, "You are not allowed to access this resource.")

    # Authn/z is legal, accept
    if verbose:
        log("DEBUG: authn accepted for user %s" % user)
    return user
Пример #8
0
 def access(self):
     """
     Record a client access
     """
     request = cherrypy.request
     remote = request.remote
     response = cherrypy.response
     inheaders = lowerCmsHeaders(request.headers)
     outheaders = response.headers
     # identify size of body from HTTP Content-Length header
     rbytes = int(cherrypy.request.headers.get('Content-Length', 0))
     if not rbytes:
         try:
             # request.rfile.rfile.bytes_read is a custom CMS web
             #  cherrypy patch not always available, hence the test
             rbytes = (getattr(request.rfile, 'rfile', None)
                     and getattr(request.rfile.rfile, "bytes_read", None)
                     and request.rfile.rfile.bytes_read) or "-"
         except:
             try:
                 # this will work only when body is read from request
                 rbytes = cherrypy.request.body.fp.bytes_read
             except:
                 rbytes = "-"        
     msg = ('%(t)s %(H)s %(h)s "%(r)s" %(s)s'
            + ' [data: %(i)s in %(b)s out %(T).0f us ]'
            + ' [auth: %(AS)s "%(AU)s" "%(AC)s" ]'
            + ' [ref: "%(f)s" "%(a)s" ]') % {'t': self.time(),
                                             'H': self.host,
                                             'h': remote.name or remote.ip,
                                             'r': request.request_line,
                                             's': response.status,
                                             'i': rbytes,
                                             'b': outheaders.get('Content-Length', '') or "-",
                                             'T': (time.time() - request.start_time) * 1e6,
                                             'AS': inheaders.get("cms-auth-status", "-"),
                                             'AU': inheaders.get("cms-auth-cert",
                                                                 inheaders.get("cms-auth-host", "")),
                                             'AC': getattr(request.cookie.get("cms-auth", None), "value", ""),
                                             'f': inheaders.get("Referer", ""),
                                             'a': inheaders.get("User-Agent", "")}
     self.access_log.log(logging.INFO, msg)
Пример #9
0
 def access(self):
     """Record one client access."""
     request = cherrypy.request
     remote = request.remote
     response = cherrypy.response
     inheaders = lowerCmsHeaders(request.headers)
     outheaders = response.headers
     wfile = request.wsgi_environ.get('cherrypy.wfile', None)
     nout = (wfile and wfile.bytes_written) or outheaders.get(
         'Content-Length', 0)
     if hasattr(request, 'start_time'):
         delta_time = (time.time() - request.start_time) * 1e6
     else:
         delta_time = 0
     msg = ('%(t)s %(H)s %(h)s "%(r)s" %(s)s'
            ' [data: %(i)s in %(b)s out %(T).0f us ]'
            ' [auth: %(AS)s "%(AU)s" "%(AC)s" ]'
            ' [ref: "%(f)s" "%(a)s" ]') % \
           {'t': self.time(),
            'H': self.host,
            'h': remote.name or remote.ip,
            'r': request.request_line,
            's': response.status,
            # request.rfile.rfile.bytes_read is a custom CMS web
            #  cherrypy patch not always available, hence the test
            'i': (getattr(request.rfile, 'rfile', None)
                  and getattr(request.rfile.rfile, "bytes_read", None)
                  and request.rfile.rfile.bytes_read) or "-",
            'b': nout or "-",
            'T': delta_time,
            'AS': inheaders.get("cms-auth-status", "-"),
            'AU': inheaders.get("cms-auth-cert", inheaders.get("cms-auth-host", "")),
            'AC': getattr(request.cookie.get("cms-auth", None), "value", ""),
            'f': inheaders.get("Referer", ""),
            'a': inheaders.get("User-Agent", "")}
     self.access_log.log(logging.INFO, msg)
     self.access_log.propagate = False  # to avoid duplicate records on the log
     self.error_log.propagate = False  # to avoid duplicate records on the log
Пример #10
0
 def access(self):
     """Record one client access."""
     request = cherrypy.request
     remote = request.remote
     response = cherrypy.response
     inheaders = lowerCmsHeaders(request.headers)
     outheaders = response.headers
     wfile = request.wsgi_environ.get('cherrypy.wfile', None)
     nout = (wfile and wfile.bytes_written) or outheaders.get('Content-Length', 0)
     if hasattr(request, 'start_time'):
         delta_time = (time.time() - request.start_time) * 1e6
     else:
         delta_time = 0
     msg = ('%(t)s %(H)s %(h)s "%(r)s" %(s)s'
            ' [data: %(i)s in %(b)s out %(T).0f us ]'
            ' [auth: %(AS)s "%(AU)s" "%(AC)s" ]'
            ' [ref: "%(f)s" "%(a)s" ]') % \
           {'t': self.time(),
            'H': self.host,
            'h': remote.name or remote.ip,
            'r': request.request_line,
            's': response.status,
            # request.rfile.rfile.bytes_read is a custom CMS web
            #  cherrypy patch not always available, hence the test
            'i': (getattr(request.rfile, 'rfile', None)
                  and getattr(request.rfile.rfile, "bytes_read", None)
                  and request.rfile.rfile.bytes_read) or "-",
            'b': nout or "-",
            'T': delta_time,
            'AS': inheaders.get("cms-auth-status", "-"),
            'AU': inheaders.get("cms-auth-cert", inheaders.get("cms-auth-host", "")),
            'AC': getattr(request.cookie.get("cms-auth", None), "value", ""),
            'f': inheaders.get("Referer", ""),
            'a': inheaders.get("User-Agent", "")}
     self.access_log.log(logging.INFO, msg)
     self.access_log.propagate = False  # to avoid duplicate records on the log
     self.error_log.propagate = False  # to avoid duplicate records on the log