Esempio n. 1
0
def application(environ, start_response):

    response_body = ""
    cn = None
    emailaddress = None
    password = None

    # schema currently may be  'autoconfig', 'autodiscover', 'mobileconfig'
    schema = None

    # subschema currently is either 'mobile' or 'outlook'
    subschema = None

    process = True
    data = None
    status = STAT_OK

    try:
        data = Config(environ)
    except Exception as e:
        process = False
        status = STAT_ERR
        print(e, file=environ["wsgi.errors"])

    if process:
        try:
            logging.basicConfig(
                filename=data.logfile,
                format='%(asctime)s %(levelname)s: %(message)s',
                level=logging.DEBUG)
        except IOError as e:
            print(e, file=environ["wsgi.errors"])

        request_method = environ['REQUEST_METHOD']
        request_method = escape(request_method)

        # Adding some more useful debugging information
        if data.debug:
            logging.debug("-" * 15 + " BEGIN environ " + "-" * 15)
            for k, v in environ.items():
                logging.debug("%s: %s" % (k, v))
            logging.debug("-" * 15 + " END environ " + "-" * 15)

        if request_method == "POST":
            try:
                request_body_size = int(environ.get('CONTENT_LENGTH', 0))
            except ValueError:
                request_body_size = 0

            # When the method is POST the query string will be sent
            # in the HTTP request body which is passed by the WSGI server
            # in the file like wsgi.input environment variable.
            request_body = environ['wsgi.input'].read(request_body_size)

            if data.debug:
                logging.debug("Request POST (raw)\n" +
                              request_body.decode('utf-8'))

            fd = StringIO(request_body.decode("utf-8"))
            fd.readline()  # Skip XML declaration
            try:
                tree = etree.parse(fd)
            except XMLSyntaxError:
                # We did not receive XML, so it might be a mobileconfig request
                # TODO: We also might check the User-Agent here
                d = parse_qs(request_body.decode('utf-8'))

                if d is not None:
                    if data.debug:
                        logging.debug(str(d))
                    if "_mobileconfig" in d:
                        mobileconfig = d["_mobileconfig"][0]
                        if mobileconfig == "true":
                            if data.debug:
                                logging.debug("Requesting mobileconfig "
                                              "configuration")
                            if "cn" in d:
                                cn = d["cn"][0]
                                cn.strip()
                            if "password" in d:
                                password = d["password"][0]
                                password.strip()
                            if "emailaddress" in d:
                                emailaddress = d["emailaddress"][0]
                                emailaddress.strip()
                                status = STAT_OK
                                schema = "mobileconfig"
                            else:
                                logging.warning("Error in mobileconfig "
                                                "request!")
                                process = False
                                status = STAT_ERR
                        else:
                            process = False
                            status = STAT_ERR
                    else:
                        process = False
                        status = STAT_ERR
                else:
                    process = False
                    status = STAT_ERR
            else:
                root = tree.getroot()

                # We need to strip the namespace for XPath
                expr = "//*[local-name() = $name]"

                response_schema = root.xpath(expr,
                                             name="AcceptableResponseSchema")
                if len(response_schema) == 0:
                    logging.warning("Error in XML request")
                    process = False
                    status = STAT_ERR
                    data.memcache.set_client()
                else:
                    # element.text is a http-URI that has a location part
                    # which we need to scan.
                    if "/mobilesync/" in response_schema[0].text:
                        subschema = "mobile"
                    elif "/outlook/" in response_schema[0].text:
                        subschema = "outlook"
                    else:
                        process = False

                    emailaddresses = root.xpath(expr, name="EMailAddress")
                    if len(emailaddresses) == 0:
                        logging.warning("Error in autodiscover request!")
                        process = False
                        status = STAT_ERR
                        data.memcache.set_client()
                    else:
                        emailaddress = emailaddresses[0].text
                        schema = "autodiscover"
                        status = STAT_OK

        elif request_method == "GET":
            # FIXME: maybe we need to catch AutoDiscover GET-REDIRECT requests
            if any("autodiscover" in s
                   for s in (environ["HTTP_HOST"],
                             environ["REQUEST_URI"].lower())):
                process = False
                status = STAT_ERR

            # autoconfig
            else:
                qs = environ['QUERY_STRING']
                d = parse_qs(qs)

                if data.debug:
                    logging.debug("Request GET: QUERY_STRING: %s" % qs)

                if d is not None:
                    if "emailaddress" in d:
                        emailaddress = d["emailaddress"][0]
                        emailaddress.strip()
                        if '@' not in emailaddress:
                            emailaddress = unquote(emailaddress)
                        status = STAT_OK
                        schema = "autoconfig"
                    else:
                        logging.warning("Error in autoconfig request!")
                        process = False
                        status = STAT_ERR
                else:
                    logging.error("Request GET: QUERY_STRING failed!")
                    process = False
                    status = STAT_ERR

    if process:
        if data.debug:
            logging.debug("Entering data.configure()")
        try:
            if data.memcache.allow_client():
                data.configure(emailaddress, cn, password)
            else:
                process = False
                status = STAT_ERR
                logging.warning(
                    "Request %d [%s] blocked!" %
                    (data.memcache.counter(), environ["REMOTE_ADDR"]))
        except DataNotFoundException:
            process = False
            status = STAT_ERR
            data.memcache.set_client()
            logging.warning("Request %d [%s]" %
                            (data.memcache.counter(), environ["REMOTE_ADDR"]))
        except Exception as e:
            if data.debug:
                tb = traceback.format_exc()
                logging.error(tb)
            else:
                logging.error("data.configure(): %s" % e)
            process = False
            status = STAT_ERR

    if process:
        if data.debug:
            logging.debug("Entering view()")
        try:
            view = View(data, schema, subschema)
            response_body = view.render()
            if len(response_body) == 0:
                status = STAT_ERR
        except Exception as e:
            if data.debug:
                tb = traceback.format_exc()
                logging.error(tb)
            else:
                logging.error("view.render(): %s" % e)
            status = STAT_ERR

    if process:
        if data.debug:
            if (schema == "mobileconfig" and "sign_mobileconfig" in data.domain
                    and data.domain["sign_mobileconfig"] is True):
                logging.debug("No debugging output for signed mobileconfig!")
            else:
                if sys.version_info < (3, ):
                    logging.debug("Response:\n" +
                                  response_body.decode('utf-8'))
                else:
                    logging.debug(str("Response:\n%s" % response_body))

    body_len = str(len(response_body))

    def aenc(key, value):
        """Auto-enocde to ascii; Make headers compatible for Py2/Py3

        :param key: header key
        :param value: header value
        :return: auto encoded tuple
        """
        if sys.version_info < (3, ):
            return key.encode("ascii"), value.encode("ascii")
        else:
            return key, value

    if schema in ('autoconfig', "autodiscover"):
        response_headers = [
            aenc('Content-Type', 'text/xml'),
            aenc('Content-Length', body_len)
        ]
    elif schema == "mobileconfig":
        response_headers = [
            aenc('Content-Type', 'application/x-apple-aspen-config'
                 '; charset=utf-8'),
            aenc('Content-Disposition', 'attachment; '
                 'filename="company.mobileconfig'),
            aenc('Content-Length', body_len)
        ]
    else:
        # Failure?
        response_headers = [
            aenc('Content-Type', 'text/html'),
            aenc('Content-Length', body_len)
        ]

    if sys.version_info < (3, ):
        status = status.encode("ascii")

    start_response(status, response_headers)

    return [response_body]
Esempio n. 2
0
def application(environ, start_response):

    response_body = ""
    cn = None
    emailaddress = None
    password = None

    # schema currently may be  'autoconfig', 'autodiscover', 'mobileconfig'
    schema = None

    # subschema currently is either 'mobile' or 'outlook'
    subschema = None

    process = True
    data = None
    status = STAT_OK

    try:
        data = Config(environ)
    except Exception as e:
        process = False
        status = STAT_ERR
        print(e, file=environ["wsgi.errors"])

    if process:
        try:
            logging.basicConfig(filename=data.logfile,
                                format='%(asctime)s %(levelname)s: %(message)s',
                                level=logging.DEBUG)
        except IOError as e:
            print(e, file=environ["wsgi.errors"])

        request_method = environ['REQUEST_METHOD']
        request_method = escape(request_method)

        # Adding some more useful debugging information
        if data.debug:
            logging.debug("-" * 15 + " BEGIN environ " + "-" * 15)
            for k, v in environ.items():
                logging.debug("%s: %s" % (k, v))
            logging.debug("-" * 15 + " END environ " + "-" * 15)

        if request_method == "POST":
            try:
                request_body_size = int(environ.get('CONTENT_LENGTH', 0))
            except ValueError:
                request_body_size = 0

            # When the method is POST the query string will be sent
            # in the HTTP request body which is passed by the WSGI server
            # in the file like wsgi.input environment variable.
            request_body = environ['wsgi.input'].read(request_body_size)

            if data.debug:
                logging.debug("Request POST (raw)\n" +
                              request_body.decode('utf-8'))

            fd = StringIO(request_body.decode("utf-8").replace(
                '<?xml version="1.0" encoding="utf-8"?>', ''))
            try:
                tree = etree.parse(fd)
            except XMLSyntaxError:
                # We did not receive XML, so it might be a mobileconfig request
                # TODO: We also might check the User-Agent here
                d = parse_qs(request_body.decode('utf-8'))

                if d is not None:
                    if data.debug:
                        logging.debug(str(d))
                    if "_mobileconfig" in d:
                        mobileconfig = d["_mobileconfig"][0]
                        if mobileconfig == "true":
                            if data.debug:
                                logging.debug("Requesting mobileconfig "
                                              "configuration")
                            if "cn" in d:
                                cn = d["cn"][0]
                                cn.strip()
                            if "password" in d:
                                password = d["password"][0]
                                password.strip()
                            if "emailaddress" in d:
                                emailaddress = d["emailaddress"][0]
                                emailaddress.strip()
                                status = STAT_OK
                                schema = "mobileconfig"
                            else:
                                logging.warning("Error in mobileconfig "
                                                "request!")
                                process = False
                                status = STAT_ERR
                        else:
                            process = False
                            status = STAT_ERR
                    else:
                        process = False
                        status = STAT_ERR
                else:
                    process = False
                    status = STAT_ERR
            else:
                root = tree.getroot()

                # We need to strip the namespace for XPath
                expr = "//*[local-name() = $name]"

                response_schema = root.xpath(expr,
                                             name="AcceptableResponseSchema")
                if len(response_schema) == 0:
                    logging.warning("Error in XML request")
                    process = False
                    status = STAT_ERR
                    data.memcache.set_client()
                else:
                    # element.text is a http-URI that has a location part
                    # which we need to scan.
                    if "/mobilesync/" in response_schema[0].text:
                        subschema = "mobile"
                    elif "/outlook/" in response_schema[0].text:
                        subschema = "outlook"
                    else:
                        process = False

                    emailaddresses = root.xpath(expr, name="EMailAddress")
                    if len(emailaddresses) == 0:
                        logging.warning("Error in autodiscover request!")
                        process = False
                        status = STAT_ERR
                        data.memcache.set_client()
                    else:
                        emailaddress = emailaddresses[0].text
                        schema = "autodiscover"
                        status = STAT_OK

        elif request_method == "GET":
            # FIXME: maybe we need to catch AutoDiscover GET-REDIRECT requests
            if any("autodiscover" in s for s in (
                    environ["HTTP_HOST"], environ["REQUEST_URI"].lower())):
                process = False
                status = STAT_ERR

            # autoconfig
            else:
                qs = environ['QUERY_STRING']
                d = parse_qs(qs)

                if data.debug:
                    logging.debug("Request GET: QUERY_STRING: %s" % qs)

                if d is not None:
                    if "emailaddress" in d:
                        emailaddress = d["emailaddress"][0]
                        emailaddress.strip()
                        if '@' not in emailaddress:
                            emailaddress = unquote(emailaddress)
                        status = STAT_OK
                        schema = "autoconfig"
                    else:
                        logging.warning("Error in autoconfig request!")
                        process = False
                        status = STAT_ERR
                else:
                    logging.error("Request GET: QUERY_STRING failed!")
                    process = False
                    status = STAT_ERR

    if process:
        if data.debug:
            logging.debug("Entering data.configure()")
        try:
            if data.memcache.allow_client():
                data.configure(emailaddress, cn, password)
            else:
                process = False
                status = STAT_ERR
                logging.warning("Request %d [%s] blocked!"
                                % (data.memcache.counter(),
                                   environ["REMOTE_ADDR"]))
        except DataNotFoundException:
            process = False
            status = STAT_ERR
            data.memcache.set_client()
            logging.warning("Request %d [%s]" % (data.memcache.counter(),
                                                 environ["REMOTE_ADDR"]))
        except Exception as e:
            if data.debug:
                tb = traceback.format_exc()
                logging.error(tb)
            else:
                logging.error("data.configure(): %s" % e)
            process = False
            status = STAT_ERR

    if process:
        if data.debug:
            logging.debug("Entering view()")
        try:
            view = View(data, schema, subschema)
            response_body = view.render()
            if len(response_body) == 0:
                status = STAT_ERR
        except Exception as e:
            if data.debug:
                tb = traceback.format_exc()
                logging.error(tb)
            else:
                logging.error("view.render(): %s" % e)
            status = STAT_ERR

    if process:
        if data.debug:
            if (schema == "mobileconfig" and
                    "sign_mobileconfig" in data.domain and
                    data.domain["sign_mobileconfig"] is True):
                logging.debug("No debugging output for signed mobileconfig!")
            else:
                if sys.version_info < (3,):
                    logging.debug("Response:\n" + response_body.decode('utf-8'))
                else:
                    logging.debug(str("Response:\n%s" % response_body))

    body_len = str(len(response_body))

    def aenc(key, value):
        """Auto-enocde to ascii; Make headers compatible for Py2/Py3

        :param key: header key
        :param value: header value
        :return: auto encoded tuple
        """
        if sys.version_info < (3,):
            return key.encode("ascii"), value.encode("ascii")
        else:
            return key, value

    if schema in ('autoconfig', "autodiscover"):
        response_headers = [aenc('Content-Type', 'text/xml'),
                            aenc('Content-Length', body_len)]
    elif schema == "mobileconfig":
        response_headers = [aenc('Content-Type',
                                 'application/x-apple-aspen-config'
                                 '; charset=utf-8'),
                            aenc('Content-Disposition',
                                 'attachment; '
                                 'filename="company.mobileconfig'),
                            aenc('Content-Length', body_len)]
    else:
        # Failure?
        response_headers = [aenc('Content-Type', 'text/html'),
                            aenc('Content-Length', body_len)]

    if sys.version_info < (3,):
        status = status.encode("ascii")

    start_response(status, response_headers)

    return [response_body]
Esempio n. 3
0
            logging.warning("Request %d [%s]" % (data.memcache.counter(),
                                                 environ["REMOTE_ADDR"]))
        except Exception, e:
            if data.debug:
                tb = traceback.format_exc()
                logging.error(tb)
            else:
                logging.error("data.configure(): %s" % e)
            process = False
            status = STAT_ERR
    
    if process:
        if data.debug:
            logging.debug("Entering view()")
        try:
            view = View(data, schema, subschema)
            response_body = view.render()
            if response_body == "":
                status = STAT_ERR
        except Exception, e:
            if data.debug:
                tb = traceback.format_exc()
                logging.error(tb)
            else:
                logging.error("view.render(): %s" % e)
            status = STAT_ERR

    if data.debug:
        if (schema == "mobileconfig" and
            data.domain.has_key("sign_mobileconfig") and
            data.domain["sign_mobileconfig"] is True):
Esempio n. 4
0
            logging.warning("Request %d [%s]" %
                            (data.memcache.counter(), environ["REMOTE_ADDR"]))
        except Exception, e:
            if data.debug:
                tb = traceback.format_exc()
                logging.error(tb)
            else:
                logging.error("data.configure(): %s" % e)
            process = False
            status = STAT_ERR

    if process:
        if data.debug:
            logging.debug("Entering view()")
        try:
            view = View(data, schema, subschema)
            response_body = view.render()
            if response_body == "":
                status = STAT_ERR
        except Exception, e:
            if data.debug:
                tb = traceback.format_exc()
                logging.error(tb)
            else:
                logging.error("view.render(): %s" % e)
            status = STAT_ERR

    if process:
        if data.debug:
            if (schema == "mobileconfig"
                    and data.domain.has_key("sign_mobileconfig")