def import_application(conn, headerid, modlog_dict, modssl_dict):
    """
    import all applications from sqlite3
    :param conn: sqlite3 connector
    :param headerid: dict to retrieve sqlite3 id of header generated in previous method
    :param modlog_dict: dict to retrieve sqlite3 id of modlog generated in previous method
    :param modssl_dict: dict to retrieve sqlite3 id of ssl profile generated in previous method
    """
    appid_application = dict()
    app_log = dict()
    appid_logid = dict()
    appid_headerid = dict()
    appid_intfid = dict()
    listenertolistenaddress = dict()
    appid_interfaceid = dict()

    cluster = Cluster.objects.get()
    node = cluster.get_current_node()
    # select the first interface which is em0
    # FIXME: ask user on which interface to bind all the listeners
    # FIXME : Obsolet method
    em = node.get_interfaces()[0].id
    
    # generate list for every table in sqlite database
    
    intf = conn.cursor()
    intf.execute("SELECT * FROM intf")
    intf_sql = intf.fetchall()

    app = conn.cursor()
    app.execute("SELECT * FROM app")
    application_sql = app.fetchall()

    app_intf = conn.cursor()
    app_intf.execute("SELECT * FROM app_intf")
    app_intf_sql = app_intf.fetchall()

    log = conn.cursor()
    log.execute("SELECT * FROM log")
    log_sql = log.fetchall()
    
    header = conn.cursor()
    header.execute("SELECT * FROM header")
    header_sql = header.fetchall()

    plugincontent = conn.cursor()
    plugincontent.execute("SELECT * FROM plugincontent")
    plugincontent_sql = plugincontent.fetchall()

    pluginheader = conn.cursor()
    pluginheader.execute("SELECT * FROM pluginheader")
    pluginheader_sql = pluginheader.fetchall()

    logger.info("Importing network interfaces")

    # Retrieve index in database of each name fields of "app_intf" table
    col_name_list_app_intf = [tuple[0] for tuple in app_intf.description]
    app_intf_id = col_name_list_app_intf.index("id")
    app_intf_app_id = col_name_list_app_intf.index("app_id")
    app_intf_intf_id = col_name_list_app_intf.index("intf_id")

    # Retrieve index in database of each name fields of "intf" table
    col_name_list_intf = [tuple[0] for tuple in intf.description]
    intf_id = col_name_list_intf.index("id")
    intf_name = col_name_list_intf.index("name")
    intf_ip = col_name_list_intf.index("ip")
    intf_port = col_name_list_intf.index("port")
    intf_log_id = col_name_list_intf.index("log_id")

    # Retrieve index in database of each name fields of "app" table
    col_name_list_app = [tuple[0] for tuple in app.description]
    app_id = col_name_list_app.index("id")
    app_friendly_name = col_name_list_app.index("friendly_name")
    app_name = col_name_list_app.index("name")
    app_url = col_name_list_app.index("url")
    app_log_id = col_name_list_app.index("log_id")
    app_logon_url = col_name_list_app.index("logon_url")
    app_auth_id = col_name_list_app.index("auth_id")
    app_auth_url = col_name_list_app.index("auth_url")
    app_Balancer_Name = col_name_list_app.index("Balancer_Name")
    app_Balancer_Node = col_name_list_app.index("Balancer_Node")
    app_enable_ssl = col_name_list_app.index("enable_ssl")
    app_ssl_configuration_id = col_name_list_app.index("ssl_configuration_id")

    # Retrieve index in database of each name fields of "log" table
    col_name_list_log = [tuple[0] for tuple in log.description]
    logs_id = col_name_list_log.index("id")
    logs_name = col_name_list_log.index("name")
    logs_level = col_name_list_log.index("level")
    logs_format = col_name_list_log.index("format")

    # Retrieve index in database of each name fields of "header" table
    col_name_list_header = [tuple[0] for tuple in header.description]
    header_id = col_name_list_header.index("id")
    header_name = col_name_list_header.index("name")
    header_type = col_name_list_header.index("type")
    header_value = col_name_list_header.index("value")
    header_app_id = col_name_list_header.index("app_id")

    # Retrieve index in database of each name fields of "pluginheader" table
    col_name_list_plugin_header = [tuple[0] for tuple in pluginheader.description]
    pluginheader_id = col_name_list_plugin_header.index("id")
    pluginheader_app_id = col_name_list_plugin_header.index("app_id")
    pluginheader_pattern = col_name_list_plugin_header.index("pattern")
    pluginheader_type = col_name_list_plugin_header.index("type")
    pluginheader_options = col_name_list_plugin_header.index("options")
    pluginheader_options1= col_name_list_plugin_header.index("options1")

    # Retrieve index in database of each name fields of "plugincontent" table
    col_name_list_plugin_content = [tuple[0] for tuple in plugincontent.description]
    plugincontent_id = col_name_list_plugin_content.index("id")
    plugincontent_app_id = col_name_list_plugin_content.index("app_id")
    plugincontent_pattern = col_name_list_plugin_content.index("pattern")
    plugincontent_type = col_name_list_plugin_content.index("type")
    plugincontent_options = col_name_list_plugin_content.index("options")
    plugincontent_options1 = col_name_list_plugin_content.index("options1")

    for i in app_intf_sql:
        appid_interfaceid[i[app_intf_app_id]] = i[app_intf_intf_id]

    # generate every listener on the current node
    for i in intf_sql:
        logger.info("Listener " + str(i[intf_name]))
        node = cluster.get_current_node()
        listener = Listener()
        listener.alias = str(i[intf_name])
        listener.ip = str(i[intf_ip])
        listener.version = "4"
        listener.prefixlen = "255.255.255.0"
        listener.is_carp = False
        listener.is_physical = False
        listener.is_gui = False
        listener.is_ghost = False
        listener.save()

        # dictionary to link listener to listen address
        listenertolistenaddress[i[intf_id]] = listener

        logger.info("Creating listener " + str(listener.alias))

        selected_intf = Interface.objects.with_id(em)
        selected_intf.inet_addresses.append(listener)  # append the listen address in the interface
        selected_intf.save()
        listener.deploy_inet()
        node.interfaces[intf_id] = selected_intf  # add the interface modified into the node
        node.save()

    appid_listenaddress = dict()
    logger.info("End of network interfaces import process")
    logger.info("Importing applications")
    for app in application_sql:

        application = Application()
        outgoing_headers = []
        content_rules = []
        headers_in = []
        public_dir = ""

        # Retrieve fqdn and public_dir from app[app_friendly_name]
        tmp = app[app_friendly_name].split("/")
        fqdn = tmp[0]
        public_dir = app[app_friendly_name].replace(fqdn, "")
        if not public_dir.endswith('/'):
            public_dir = public_dir + '/'

        # if there's an authentication portal (app[app_logon_url]) then auth = True
        if app[app_logon_url] is None:
            need_auth = False
        else:
            need_auth = True

        # retrieve type of application
        if app[app_url].split(":")[0] == "balancer":  # if the url start with "balancer://" , app_type=balanced
            app_type = "balanced"
            # [app_Balancer_Name] = balancer uri
            application.proxy_balancer = ProxyBalancer.objects.get(name=app[app_Balancer_Name])
        else:
            app_type = app[app_url].split(":")[0]  # otherwise; filetype is before ":" (http,https,ftp...)

        # retrieve log profile linked to this app (we generated the profile earlier, now we find it back)
        for j in log_sql:
            if app[app_log_id] == j[logs_id]:  # if app[app_log_id] =logs_id of the application match => link
                app_log[app[app_friendly_name]] = j[logs_level]  # link appname -> log_level found
                appid_logid[app[app_id]] = j[logs_id]

        # generate a listen_address for this app based on the interface generated earlier
        for j in intf_sql:
            if appid_interfaceid[app[app_id]] == j[intf_id]:  # find link  between interface and app_id
                interface_id = j[intf_id]
                intf.execute("SELECT * FROM intf WHERE id =?", (interface_id,))  # select interface in db with link
                interface = intf.fetchone()
                appid_intfid[app[app_id]] = interface[0]  # appid_interfaceid appid:interfaceid
                listen_address = ListenAddress()
                # apprend address of listener to current listen address
                listen_address.address = listenertolistenaddress[j[intf_id]]
                listen_address.port = str(j[intf_port])
                listen_address.redirect = False
                listen_address.redirect_port = ""
                # if this app uses a specific SSL profile, then load it
                if app[app_enable_ssl] == 1:
                    listen_address.ssl_profile = modssl_dict[app[app_ssl_configuration_id]]
                listen_address.save()
                appid_listenaddress[app[app_id]] = listen_address

        # Retrieve all request headers except SSL headers (not managed in vulture3)
        for j in header_sql:
            if app[app_id] == j[header_app_id]:
                if j[header_name] != "SSL_CLIENT_S_DN_CN" and \
                                j[header_name] != "SSL_CLIENT_S_DN_O" and j[header_name] != "SSL_CLIENT_S_DN_OU":
                    appid_headerid[str(app[app_id])] = j[header_id]
                    headers_in.append(headerid[j[header_id]])

        # Retrieve headers in "pluginheader" table
        for j in pluginheader_sql:
            if j[pluginheader_app_id] == app[app_id]:
                headerin = HeaderIn()
                headerin.name = j[pluginheader_pattern]
                headerin.action = "edit"
                headerin.value = j[pluginheader_options]
                headerin.replacement = j[pluginheader_options1]
                headerin.condition = "always"
                headerin.save()
                headers_in.append(headerin)

        """ generate each type of header out and contentrule. Stored in the same table "plugincontent"
         with non consistent fields."""
        for i in plugincontent_sql:
            if i[plugincontent_type] == "Rewrite Content" and i[plugincontent_app_id] == app[app_id]:
                content_rule = ContentRule()
                content_rule.path_type = "files"
                content_rule.path = ""
                content_rule.types = ""
                content_rule.flags = ""
                content_rule.deflate = True
                content_rule.inflate = False
                content_rule.pattern = i[plugincontent_pattern]
                content_rule.replacement = i[plugincontent_options]
                content_rule.save()
                content_rules.append(content_rule)
            if i[plugincontent_type] == "Rewrite Link" and i[plugincontent_app_id] == app[app_id]:
                headerout = HeaderOut()
                headerout.name = "Link"
                headerout.value = i[plugincontent_options]
                headerout.replacement = i[plugincontent_pattern]
                headerout.action = "edit"
                headerout.condition = "always"
                headerout.save()
                outgoing_headers.append(headerout)
            if i[plugincontent_type] == "Location" and i[plugincontent_app_id] == app[app_id]:
                headerout = HeaderOut()
                headerout.name = i[plugincontent_pattern]
                headerout.value = i[plugincontent_options1]
                headerout.replacement = i[plugincontent_options]
                headerout.action = "edit"
                headerout.condition = "always"
                headerout.save()
                outgoing_headers.append(headerout)

        # retrieve the Vulture Internal Database repository for authentication.
        repo_list = BaseAbstractRepository.get_auth_repositories()
        for repo in repo_list:
            if repo.is_internal and isinstance(repo.get_backend(), MongoEngineBackend):
                auth_backend = repo

        # select the default worker
        worker = Worker.objects.first()
        # auth_backend = ""
        # populate each field of app generated before
        application.name = app[app_friendly_name]
        application.type = app_type
        application.public_name = fqdn
        application.private_uri = app[app_url]
        application.public_dir = public_dir
        application.proxy_add_header = False
        application.access_mode = []
        # retrieve log profile generated that have a link with this app
        for j in log_sql:
            application.log_custom = modlog_dict[appid_logid[app[app_id]]]
            tmp = application.log_custom.format
            tmp = tmp.replace("\\", "")  # remove escaping chars from mongo
            application.log_custom.format = tmp
        application.log_level = app_log[app[app_friendly_name]]
        application.headers_in = headers_in
        application.headers_out = outgoing_headers
        application.content_rules = content_rules
        application.listeners.append(appid_listenaddress[app[app_id]])
        application.force_tls = False
        application.worker = worker
        application.methods = "HEAD,GET,POST"
        application.enable_h2 = False
        application.enable_rpc = False
        application.need_auth = need_auth
        if need_auth:
            application.auth_type = "basic"
            application.auth_backend = str(auth_backend)
            application.auth_backend_fallback = str(auth_backend)
            application.auth_portal = str(application.private_uri + app[app_logon_url])
            application.auth_timeout = "900"
            application.auth_timeout_restart = True
        application.sso_enabled = False
        if application.sso_enabled:
            application.sso_forward = "form"
            application.sso_forward_basic_mode = "autologon"
            application.sso_forward_only_login = False
            application.sso_forward_basic_url = "http=//your_internal_app/action.do?what=login"
            application.sso_forward_follow_redirect = False
            application.sso_forward_return_post = False
            application.sso_forward_content_type = "default"
            application.sso_url = "http://your_internal_app/action.do?what=login"
            application.sso_vulture_agent = False
            application.sso_capture_content_enabled = False
            application.sso_capture_content = ""
            application.sso_replace_content_enabled = False
            application.sso_replace_content = "By previously captured '$1'/"
            application.sso_after_post_request_enabled = False
            application.sso_after_post_request = "http://My_Responsive_App.com/Default.aspx"
            application.sso_after_post_replace_content_enabled = False
            application.sso_after_post_replace_content = ""
        logger.info("Saving application: " + str(application))
        application.save()
        appid_application[app[app_id]] = application.id
    logger.info("End of applications import process")
    return appid_application
Exemple #2
0
def edit(request, object_id=None):
    """ View dedicated to application management

    :param object_id: MongoDB object_id of application
    :param request: Django request object
    """
    # Retrieving application configuration
    application = Application.objects.with_id(ObjectId(object_id))

    specific_rules_set = []
    incoming_headers = []
    outgoing_headers = []
    content_rules = []
    listeners = []
    listeners_ips = []
    svms = []
    activated_svms = []

    # Application doesn"'t exist ==> We want to create a new one
    # Fix some default values
    if not application and request.method != 'POST':
        application = Application(name="My App",
                                  type="http",
                                  public_name="www.example.com",
                                  public_alias="www.ex_1.fr",
                                  public_dir="/",
                                  private_uri="https://192.168.1.1/owa/")
        # Fix default security rules
        incoming_headers.append(
            HeaderOut(True, 'unset', '^X-Forwarded-', '', '', 'always', ''))
        # outgoing_headers.append(HeaderOut ('set', 'Content-Security-Policy', 'default-src \'self\'', '', 'always', ''))
        outgoing_headers.append(
            HeaderOut(True, 'set', 'X-Frame-Options', 'SAMEORIGIN', '',
                      'always', ''))
        outgoing_headers.append(
            HeaderOut(True, 'set', 'X-Content-Type-Options', 'nosniff', '',
                      'always', ''))
        outgoing_headers.append(
            HeaderOut(True, 'set', 'X-XSS-Protection', '1; mode=block', '',
                      'always', ''))
        application.headers_in = incoming_headers
        application.headers_out = outgoing_headers

    # Check if request are valid - and populate arrays with form values
    if request.method == 'POST':
        dataPosted = request.POST
        dataPostedRaw = str(request.body).split("&")

        has_listener = False
        dataPosted_length = len(dataPostedRaw)

        if application and not "enabled=on" in dataPostedRaw:
            application.delete_listeners()

        for data in dataPostedRaw:
            if data.startswith("address_"):
                # Listener management
                for cpt in range(dataPosted_length):
                    if data.startswith("address_" + str(cpt) + "="):

                        inet = None
                        port = None
                        redirect_port = None

                        try:
                            listener_id = dataPosted['address_' + str(cpt)]
                            inet = Listener.objects.with_id(
                                ObjectId(listener_id))
                        except Exception as e:
                            pass

                        try:
                            port = dataPosted['port_' + str(cpt)]
                        except Exception as e:
                            pass

                        try:
                            redirect_port = dataPosted['redirect_port_' +
                                                       str(cpt)]
                        except Exception as e:
                            pass

                        try:
                            ssl_profile = ModSSL.objects.with_id(
                                ObjectId(dataPosted['ssl_profile_' +
                                                    str(cpt)]))
                        except Exception as e:
                            ssl_profile = None
                            pass

                        if (inet and port):

                            address = ListenAddress(
                                address=inet,
                                port=port,
                                ssl_profile=ssl_profile,
                                redirect_port=redirect_port)
                            """ Add '1' because we don't want to save yet the listener """
                            address.related_node = address.get_related_node(1)
                            listeners.append(address)
                            listeners_ips.append(
                                (address.related_node, inet.ip, port))
                            has_listener = True

                        dataPosted_length -= 4

            if data.startswith("SpecificRS_url_"):
                for cpt in range(dataPosted_length):
                    if data.startswith("SpecificRS_url_" + str(cpt) + "="):

                        # Force default values to prevent injection or any problem
                        specific_rs_url = dataPosted.get(
                            'SpecificRS_url_' + str(cpt), '/login/')
                        try:
                            specific_rs_rs = ModSecRulesSet.objects.with_id(
                                ObjectId(
                                    dataPosted.get(
                                        'modsec_specific_rs_select' + str(cpt),
                                        None)))
                        except:
                            specific_rs_rs = ModSecRulesSet.objects.first()

                        specific_rs = ModSecSpecificRulesSet(
                            url=specific_rs_url, rs=specific_rs_rs)
                        specific_rules_set.append(specific_rs)

                        cpt -= 2

            # Incoming header management
            if data.startswith("header_action_"):
                for cpt in range(dataPosted_length):
                    if data.startswith("header_action_" + str(cpt) + "="):

                        # Force harmless default values to prevent any injection or jQuery problem
                        header_enable = (dataPosted.get(
                            'header_enable_' + str(cpt), 'off') == 'on')
                        header_action = dataPosted.get(
                            'header_action_' + str(cpt), 'add')
                        header_name = dataPosted.get('header_name_' + str(cpt),
                                                     'Vulture')
                        header_value = dataPosted.get(
                            'header_value_' + str(cpt), '')
                        header_replacement = dataPosted.get(
                            'header_replacement_' + str(cpt), '')
                        header_condition = dataPosted.get(
                            'header_condition_' + str(cpt), 'always')
                        header_condition_v = dataPosted.get(
                            'header_condition_v_' + str(cpt), '')

                        # FIXME: Coherence control
                        header = HeaderIn(header_enable, header_action,
                                          header_name, header_value,
                                          header_replacement, header_condition,
                                          header_condition_v)
                        incoming_headers.append(header)

                        dataPosted_length -= 7

            # Outgoing header management
            if data.startswith("header_out_action_"):
                for cpt in range(dataPosted_length):
                    if data.startswith("header_out_action_" + str(cpt) + "="):

                        # Force harmless default values to prevent any injection or jQuery problem
                        header_enable = (dataPosted.get(
                            'header_out_enable_' + str(cpt), 'off') == 'on')
                        header_action = dataPosted.get(
                            'header_out_action_' + str(cpt), 'add')
                        header_name = dataPosted.get(
                            'header_out_name_' + str(cpt), 'Vulture')
                        header_value = dataPosted.get(
                            'header_out_value_' + str(cpt), '')
                        header_replacement = dataPosted.get(
                            'header_out_replacement_' + str(cpt), '')
                        header_condition = dataPosted.get(
                            'header_out_condition_' + str(cpt), 'always')
                        header_condition_v = dataPosted.get(
                            'header_out_condition_v_' + str(cpt), '')

                        # FIXME: Coherence control
                        header = HeaderOut(header_enable, header_action,
                                           header_name, header_value,
                                           header_replacement,
                                           header_condition,
                                           header_condition_v)
                        outgoing_headers.append(header)

                        dataPosted_length -= 7

            # # Content rules management
            if data.startswith("content_types_"):
                for cpt in range(dataPosted_length):
                    if data.startswith("content_types_" + str(cpt) + "="):

                        # Force harmless default values to prevent any injection
                        # or jQuery problem
                        content_enable = True if dataPosted.get(
                            'content_enable_' +
                            str(cpt), 'off') == 'on' else False
                        content_types = dataPosted.get(
                            'content_types_' + str(cpt), 'text/html')
                        content_condition = dataPosted.get(
                            'condition_' + str(cpt), '')
                        content_deflate = True if dataPosted.get(
                            'content_deflate_' +
                            str(cpt), 'off') == 'on' else False
                        content_inflate = True if dataPosted.get(
                            'content_inflate_' +
                            str(cpt), 'off') == 'on' else False
                        content_pattern = dataPosted.get(
                            'content_pattern_' + str(cpt), '')
                        content_replacement = dataPosted.get(
                            'content_replacement_' + str(cpt), '')
                        content_replacement_flags = dataPosted.get(
                            'content_replacement_flags_' + str(cpt), '')

                        # FIXME: Coherence control
                        rule = ContentRule(content_enable, content_types,
                                           content_condition, content_deflate,
                                           content_inflate, content_pattern,
                                           content_replacement,
                                           content_replacement_flags)
                        content_rules.append(rule)

                        dataPosted_length -= 8

            # SVMs management
            if data.startswith("checkbox_chart_uri_analysis_"):
                m = re.match('checkbox_chart_uri_analysis_([0-9|a-f]+)', data)
                if m:
                    dataset_id_ = m.group(1)

                    # Force harmless default values to prevent any injection or jQuery problem
                    svm_enable = False
                    try:
                        svm_enable = True if dataPosted.get(
                            'checkbox_chart_uri_analysis_' +
                            dataset_id_) == 'on' else False
                        if svm_enable:
                            svm = SVM.objects(dataset_used=dataset_id_,
                                              algo_used="Levenstein")[0]
                            activated_svms.append(str(svm.id))
                            logger.debug(
                                "Activated SVM with id '{}' for application saved"
                                .format(str(svm.id)))
                    except KeyError:
                        pass
                    except Exception as e:
                        logger.error(
                            "Unable to retrieve activated SVM - Dataset_id:{}, algo_used:Levenstein - Exception: {}"
                            .format(dataset_id_, str(e)))

            if data.startswith("checkbox_chart_uri_analysis_2_"):
                m = re.match('checkbox_chart_uri_analysis_2_([0-9|a-f]+)',
                             data)
                if m:
                    dataset_id_ = m.group(1)

                    # Force harmless default values to prevent any injection or jQuery problem
                    svm_enable = False
                    try:
                        svm_enable = True if dataPosted.get(
                            'checkbox_chart_uri_analysis_2_' +
                            dataset_id_) == 'on' else False
                        if svm_enable:
                            svm = SVM.objects(dataset_used=dataset_id_,
                                              algo_used="Levenstein2")[0]
                            activated_svms.append(str(svm.id))
                            logger.debug(
                                "Activated SVM with id '{}' for application saved"
                                .format(str(svm.id)))
                    except KeyError:
                        pass
                    except Exception as e:
                        logger.error(
                            "Unable to retrieve activated SVM - Dataset_id:{}, algo_used:Levenstein2 - Exception: {}"
                            .format(dataset_id_, str(e)))

            if data.startswith("checkbox_chart_bytes_received_"):
                m = re.match('checkbox_chart_bytes_received_([0-9|a-f]+)',
                             data)
                if m:
                    dataset_id_ = m.group(1)

                    # Force harmless default values to prevent any injection or jQuery problem
                    svm_enable = False
                    try:
                        svm_enable = True if dataPosted.get(
                            'checkbox_chart_bytes_received_' +
                            dataset_id_) == 'on' else False
                        if svm_enable:
                            svm = SVM.objects(
                                dataset_used=dataset_id_,
                                algo_used="HTTPcode_bytes_received")[0]
                            activated_svms.append(str(svm.id))
                            logger.debug(
                                "Activated SVM with id '{}' for application saved"
                                .format(str(svm.id)))
                    except KeyError:
                        pass
                    except Exception as e:
                        logger.error(
                            "Unable to retrieve activated SVM - Dataset_id:{}, algo_used:HTTPcode_bytes_received - Exception: {}"
                            .format(dataset_id_, str(e)))

            if data.startswith("checkbox_chart_ratio_"):
                m = re.match('checkbox_chart_ratio_([0-9|a-f]+)', data)
                if m:
                    dataset_id_ = m.group(1)

                    # Force harmless default values to prevent any injection or jQuery problem
                    svm_enable = False
                    try:
                        svm_enable = True if dataPosted.get(
                            'checkbox_chart_ratio_' +
                            dataset_id_) == 'on' else False
                        if svm_enable:
                            svm = SVM.objects(dataset_used=dataset_id_,
                                              algo_used="Ratio")[0]
                            activated_svms.append(str(svm.id))
                            logger.debug(
                                "Activated SVM with id '{}' for application saved"
                                .format(str(svm.id)))
                    except KeyError:
                        pass
                    except Exception as e:
                        logger.error(
                            "Unable to retrieve activated SVM - Dataset_id:{}, algo_used:Ratio - Exception: {}"
                            .format(dataset_id_, str(e)))

        form = ApplicationForm(request.POST,
                               instance=application,
                               listeners=listeners)
    else:

        if not object_id:
            try:
                rulesset_vulture = [
                    ModSecRulesSet.objects.get(name="Vulture RS").id
                ]
            except ModSecRulesSet.DoesNotExist:
                rulesset_vulture = []

            form = ApplicationForm(initial={
                "rules_set":
                rulesset_vulture,
                "modsec_policy":
                ModSec.objects.get(name="Default Policy")
            },
                                   instance=application)
        else:
            form = ApplicationForm(
                initial={'rules_set': [x.id for x in application.rules_set]},
                instance=application)

        incoming_headers = application.headers_in
        outgoing_headers = application.headers_out
        content_rules = application.content_rules

        specific_rules_set = list()
        for i in application.specific_rules_set:
            specific_rules_set.append(
                ModSecSpecificRulesSet(url=re.sub('^' + application.public_dir,
                                                  '', i.url),
                                       rs=i.rs))

        # We replace '\' by '\\' in strings because they're interpreted by templates
        for tmp_rule in content_rules:
            tmp_rule.pattern = tmp_rule.pattern.replace("\\", "\\\\")
            tmp_rule.replacement = tmp_rule.replacement.replace("\\", "\\\\")

        listeners = application.listeners

        svms = [
            SVM.objects(id=ObjectId(svm_id)).no_dereference().only(
                'dataset_used', 'algo_used', 'id').first()
            for svm_id in application.activated_svms
        ]

    # Saving information into database and redirect to application list
    if request.method == 'POST' and form.is_valid():

        # Listener is mandatory
        if has_listener:
            old_app = Application.objects.with_id(ObjectId(object_id))

            # 1) Remove old listeners, headers and content rules
            if old_app and old_app.listeners:
                for listener in old_app.listeners:
                    ip = listener.address.ip
                    port = listener.port
                    n = listener.related_node
                    """ Stop the listener if there is only this app running on it """
                    if (n, ip, port) not in listeners_ips:
                        logger.info("Stopping listener {}:{}".format(ip, port))
                        listener.stop()

                    listener.delete()

            if old_app and old_app.headers_in:
                for header in old_app.headers_in:
                    header.delete()

            if old_app and old_app.headers_out:
                for header in old_app.headers_out:
                    header.delete()

            if old_app and old_app.content_rules:
                for rule in old_app.content_rules:
                    rule.delete()

            if old_app and old_app.specific_rules_set:
                for ruleset in old_app.specific_rules_set:
                    ruleset.delete()

            old_cookie_encryption = False
            old_cookie_cipher = None
            if old_app:
                application.wl_bl_rules = old_app.wl_bl_rules

                old_cookie_encryption = old_app.cookie_encryption
                old_cookie_cipher = old_app.cookie_cipher
                old_cookie_cipher_key = old_app.cookie_cipher_key
                old_cookie_cipher_iv = old_app.cookie_cipher_iv

            # 2) Create new listeners, headers and content rules
            for listener in listeners:
                listener.save()
            for header in incoming_headers:
                header.save()
            for header in outgoing_headers:
                header.save()
            for rule in content_rules:
                rule.save()

            # 3) Assign listeners, headers and content rules
            auth_backend = form.cleaned_data.get('auth_backend')
            auth_backend_fallbacks = form.cleaned_data.get(
                'auth_backend_fallbacks')
            application = form.save(commit=False)

            if auth_backend:
                application.auth_backend = auth_backend
            else:
                application.auth_backend = None
            if auth_backend_fallbacks:
                application.auth_backend_fallbacks = auth_backend_fallbacks
            else:
                application.auth_backend_fallbacks = None

            application.listeners = listeners
            application.headers_in = incoming_headers
            application.headers_out = outgoing_headers
            application.specific_rules_set = specific_rules_set
            application.content_rules = content_rules
            application.activated_svms = activated_svms

            if application.cookie_encryption:
                if not old_cookie_encryption or not old_cookie_cipher or application.cookie_cipher != old_cookie_cipher:
                    application.cookie_cipher_key = get_random_string(
                        32
                    ) if application.cookie_cipher == 'aes256' else get_random_string(
                        16)
                    application.cookie_cipher_iv = get_random_string(
                        32
                    ) if application.cookie_cipher == 'aes256' else get_random_string(
                        16)

                else:
                    application.cookie_cipher_key = old_cookie_cipher_key
                    application.cookie_cipher_iv = old_cookie_cipher_iv

            # 4) Save application
            if not application.public_dir.endswith('/'):
                application.public_dir += '/'
            if application.auth_portal and not application.auth_portal.endswith(
                    '/'):
                application.auth_portal += '/'
            if application.private_uri and not application.private_uri.endswith(
                    '/'):
                application.private_uri += '/'

            for ruleset in specific_rules_set:
                ruleset.url = os.path.normpath(
                    str(application.public_dir) + '/' + str(ruleset.url))
                ruleset.save()

            if not object_id:
                # Create BlackList/WhiteList ModSecRuleSet
                modsec_wl_bl = ModSecRulesSet(
                    name="{} whitelist/blacklist".format(application.name),
                    type_rule="wlbl")
                modsec_wl_bl.save()
                modsec_wl_bl.conf = modsec_wl_bl.get_conf()
                modsec_wl_bl.save()

                application.wl_bl_rules = modsec_wl_bl

            else:
                # If the application is modified, modify the name of the RS references
                application.wl_bl_rules.name = "{} whitelist/blacklist".format(
                    form.cleaned_data.get('name'))
                application.wl_bl_rules.save()
                for modsec_ruleset in ModSecRulesSet.objects.filter(
                        name="Learning {} WL"):
                    modsec_ruleset.name = form.cleaned_data.get('name')
                    modsec_ruleset.save()

            if application.type == "balanced":
                application.private_uri = "{}://{}".format(
                    application.proxy_balancer.members[0].uri_type,
                    application.proxy_balancer.members[0].uri)

            # Check if api_call to reload rsyslogd is needed
            if old_app:
                if application.log_custom != old_app.log_custom or application.log_level != old_app.log_level or application.learning != old_app.learning:
                    application.save()
                else:
                    application.save(no_apicall=True)
            else:
                application.save()

            return HttpResponseRedirect('/application/')

    inets = Listener.objects()
    address_list = list()
    vhid_list = list()
    # List and categorize inet (carp or not) to render them in template
    for inet in inets:
        listener = dict()
        if inet.is_carp:
            listener['inet'] = inet
            listener['id'] = getattr(inet, 'id')
            vhid_list.append(inet.carp_vhid)

        elif inet.carp_vhid in vhid_list:
            continue

        else:
            listener['inet'] = inet
            listener['id'] = getattr(inet, 'id')

        address_list.append(listener)

    ssl_profile_list = ModSSL.objects()

    rules_set_list = ModSecRulesSet.objects.filter(
        type_rule__in=['crs', 'trustwave', 'vulture', 'custom'])

    return render_to_response('application_edit.html', {
        'form': form,
        'object_id': object_id,
        'headers_in': incoming_headers,
        'headers_out': outgoing_headers,
        'content_rules': content_rules,
        'listeners': listeners,
        'address_list': address_list,
        'ssl_profile_list': ssl_profile_list,
        'application': application,
        'svms': svms,
        'rules_set_list': rules_set_list,
        'specific_rules_set': specific_rules_set
    },
                              context_instance=RequestContext(request))