Пример #1
0
def save_user_account(username, data, user):
    data = validate_settings(data,
                             ACCOUNT_DEFAULT,
                             exceptions=[
                                 'avatar', 'agrees_with_tos', 'dn', 'password',
                                 'otp_sk', 'u2f_devices'
                             ])

    if username != data['uname']:
        raise AccessDeniedException(
            "You are not allowed to change the username.")

    if username != user['uname'] and not user['is_admin']:
        raise AccessDeniedException(
            "You are not allowed to change another user then yourself.")

    current = STORAGE.get_user_account(username)
    if current:
        current = validate_settings(current,
                                    ACCOUNT_DEFAULT,
                                    exceptions=[
                                        'avatar', 'agrees_with_tos', 'dn',
                                        'password', 'otp_sk', 'u2f_devices'
                                    ])

        if not user['is_admin']:
            for key in current.iterkeys():
                if data[key] != current[
                        key] and key not in ACCOUNT_USER_MODIFIABLE:
                    raise AccessDeniedException(
                        "Only Administrators can change the value of the field [%s]."
                        % key)
    else:
        raise InvalidDataException(
            "You cannot save a user that does not exists [%s]." % username)

    if not data['avatar']:
        STORAGE.delete_user(data['uname'] + "_avatar")
    else:
        STORAGE.set_user_avatar(username, data['avatar'])
    data['avatar'] = None

    return STORAGE.set_user_account(username, data)
Пример #2
0
def set_service(servicename, **_):
    """
    Save the configuration of a given service
    
    Variables: 
    servicename    => Name of the service to save
    
    Arguments: 
    None
    
    Data Block:
    {'accepts': '(archive|executable|java|android)/.*',
     'category': 'Extraction',
     'classpath': 'al_services.alsvc_extract.Extract',
     'config': {'DEFAULT_PW_LIST': ['password', 'infected']},
     'cpu_cores': 0.1,
     'description': "Extract some stuff",
     'enabled': True,
     'install_by_default': True,
     'name': 'Extract',
     'ram_mb': 256,
     'rejects': 'empty|metadata/.*',
     'stage': 'EXTRACT',
     'submission_params': [{'default': u'',
       'name': 'password',
       'type': 'str',
       'value': u''},
      {'default': False,
       'name': 'extract_pe_sections',
       'type': 'bool',
       'value': False},
      {'default': False,
       'name': 'continue_after_extract',
       'type': 'bool',
       'value': False}],
     'supported_platforms': ['Linux'],
     'timeout': 60}
    
    Result example:
    {"success": true }    #Saving the user info succeded
    """
    data = request.json

    try:
        if servicename != data['name']:
            raise AccessDeniedException(
                "You are not allowed to change the service name.")

        return make_api_response(
            {"success": STORAGE.save_service(servicename, data)})
    except AccessDeniedException, e:
        return make_api_response({"success": False}, e.message, 403)
Пример #3
0
def set_host(mac, *args, **kwargs):
    """
    Set the host information
    
    Variables: 
    mac       => MAC Address of the host to get the info
    
    Arguments:
    None
    
    Data Block:
    {
     "profile": "Default profile",  # Host current profile 
     "machine_info": {              # Host Machine info block
       "uid": "Core-001122334455",    # Machine UID
       "ip": "127.0.0.1",             # Machine IP
       "memory": "23.5",              # Machine RAM (GB)
       "cores": 16,                   # Machine Num Cores
       "os": "Linux",                 # Machine OS
       "name": "computer1" },         # Machine Name
     "ip": "127.0.0.1",             # Host IP
     "hostname": "computer1",       # Host Name
     "enabled": true,               # Is host enabled?
     "platform": {                  # Host platform block
       "node": "computer1",           # Node name
       "system": "Linux",             # Node system
       "machine": "x86_64",           # Node Architecture
       "version": "#47-Ubuntu SMP",   # Node Kernel version
       "release": "3.13.0-24",        # Node Kernel release
       "proc": "x86_64" },            # Node proc Architecture
     "mac_address": "001122334455"  # Host Mac address
    }
    
    Result example:
    {
     "status": "success"            # Was saving successful ?
    }
    """
    
    data = request.json
    
    if mac != data['mac_address']:
        raise AccessDeniedException("You are not allowed to change the host MAC Address.")
    
    return make_api_response(STORAGE.save_node(mac, data))
Пример #4
0
def set_virtual_machine(vm, **_):
    """
    Save the configuration of a given virtual machine
    
    Variables: 
    vm    => Name of the virtual machine
    
    Arguments: 
    None
    
    Data Block:
    { 
     enabled: true,                  # Is VM enabled
     name: "Extract",                # Name of the VM
     num_workers: 1,                 # Number of workers
     os_type: "windows",             # Type of OS
     os_variant: "win7",             # Variant of OS
     ram: 1024,                      # Amount of RAM
     revert_every: 600,              # Auto revert seconds intervale
     vcpus: 1,                       # Number of CPUs
     virtual_disk_url: "img.qcow2"   # Name of the virtual disk to download
    }
    
    Result example:
    {"success": true }    #Saving the virtual machine info succeded
    """
    data = request.json

    try:
        if vm != data['name']:
            raise AccessDeniedException(
                "You are not allowed to change the virtual machine name.")

        return make_api_response(
            {"success": STORAGE.save_virtualmachine(vm, data)})
    except AccessDeniedException, e:
        return make_api_response({"success": False}, e.message, 403)
Пример #5
0
def login(uname, path=None):
    user = STORAGE.get_user_account(uname)
    if not user:
        raise AccessDeniedException("User %s does not exists" % uname)

    if not user['is_active']:
        raise AccessDeniedException("User %s is disabled" % uname)

    add_access_control(user)

    if path:
        user["submenu"] = [{
            "icon": "glyphicon-user",
            "active": path.startswith("/account.html"),
            "link": "/account.html",
            "title": "Account"
        }, {
            "icon": "glyphicon-tasks",
            "active": path.startswith("/dashboard.html"),
            "link": "/dashboard.html",
            "title": "Dashboard"
        }, {
            "icon": "glyphicon-cog",
            "active": path.startswith("/settings.html"),
            "link": "/settings.html",
            "title": "Settings"
        }, {
            "icon": "glyphicon-log-out",
            "active": path.startswith("/logout.html"),
            "link": "/logout.html",
            "title": "Sign out"
        }]

        if user['is_admin']:
            user['menu_active'] = (path.startswith("/settings.html")
                                   or path.startswith("/account.html")
                                   or path.startswith("/admin/")
                                   or path.startswith("/dashboard.html")
                                   or path.startswith("/kibana-dash.html"))
            if config.logging.logserver.node:
                user["kibana_dashboards"] = [{
                    "icon":
                    None,
                    "active":
                    path.startswith("/kibana-dash.html?dash=%s" % x),
                    "link":
                    "/kibana-dash.html?dash=%s" % x,
                    "title":
                    "%s" % x.replace("-", " ")
                } for x in config.logging.logserver.kibana.dashboards
                                             if x != ""]
            user["admin_menu"] = [{
                "icon": None,
                "active": path.startswith("/admin/seed.html"),
                "link": "/admin/seed.html",
                "title": "Configuration"
            }, {
                "icon":
                None,
                "active":
                path.startswith("/admin/documentation.html"),
                "link":
                "/admin/documentation.html",
                "title":
                "Documentation"
            }, {
                "icon":
                None,
                "active":
                path.startswith("/admin/errors.html"),
                "link":
                "/admin/errors.html",
                "title":
                "Errors viewer"
            }, {
                "icon":
                None,
                "active":
                path.startswith("/admin/hosts.html"),
                "link":
                "/admin/hosts.html",
                "title":
                "Hosts"
            }, {
                "icon":
                None,
                "active":
                path.startswith("/admin/profiles.html"),
                "link":
                "/admin/profiles.html",
                "title":
                "Profiles"
            }, {
                "icon":
                None,
                "active":
                path.startswith("/admin/provisioning.html"),
                "link":
                "/admin/provisioning.html",
                "title":
                "Provisioning"
            }, {
                "icon":
                None,
                "active":
                path.startswith("/admin/services.html"),
                "link":
                "/admin/services.html",
                "title":
                "Services"
            }, {
                "icon":
                None,
                "active":
                path.startswith("/admin/site_map.html"),
                "link":
                "/admin/site_map.html",
                "title":
                "Site Map"
            }, {
                "icon":
                None,
                "active":
                path.startswith("/admin/users.html"),
                "link":
                "/admin/users.html",
                "title":
                "Users"
            }, {
                "icon":
                None,
                "active":
                path.startswith("/admin/virtual_machines.html"),
                "link":
                "/admin/virtual_machines.html",
                "title":
                "Virtual Machines"
            }]
        else:
            user['menu_active'] = (path.startswith("/settings.html")
                                   or path.startswith("/account.html")
                                   or path.startswith("/dashboard.html"))
            user["kibana_dashboards"] = []
            user["admin_menu"] = []

    user['2fa_enabled'] = user.pop('otp_sk', None) is not None
    user['allow_2fa'] = config.auth.get('allow_2fa', True)
    user['allow_apikeys'] = config.auth.get('allow_apikeys', True)
    user['allow_u2f'] = config.auth.get('allow_u2f', True)
    user['apikeys'] = [x[0] for x in user.get('apikeys', [])]
    user['c12n_enforcing'] = config.system.classification.definition.enforce
    user['has_password'] = user.pop('password', None) is not None
    user['internal_auth_enabled'] = config.auth.internal.enabled
    user['u2f_enabled'] = len(user.pop('u2f_devices', [])) != 0

    return user
Пример #6
0
        def base(*args, **kwargs):
            # Login
            session_id = flsk_session.get("session_id", None)

            if not session_id:
                abort(401)

            session = KV_SESSION.get(session_id)

            if not session:
                abort(401)
            else:
                session = json.loads(session)
                cur_time = now()
                if session.get('expire_at', 0) < cur_time:
                    KV_SESSION.pop(session_id)
                    abort(401)
                else:
                    session['expire_at'] = cur_time + session.get(
                        'duration', 3600)

            if request.headers.get("X-Forward-For", None) != session.get('ip', None) or \
                    request.headers.get("User-Agent", None) != session.get('user_agent', None):
                abort(401)

            KV_SESSION.set(session_id, session)

            logged_in_uname = session.get("username", None)

            if not set(self.required_priv).intersection(
                    set(session.get("privileges", []))):
                raise AccessDeniedException(
                    "The method you've used to login does not give you access to this API."
                )

            if "E" in session.get("privileges", []) and self.check_xsrf_token and \
                    session.get('xsrf_token', "") != request.environ.get('HTTP_X_XSRF_TOKEN', ""):
                raise AccessDeniedException("Invalid XSRF token.")

            # Impersonation
            requestor = request.environ.get("HTTP_X_PROXIEDENTITIESCHAIN",
                                            None)
            temp_user = login(logged_in_uname)

            # Terms of Service
            if not request.path == "/api/v3/user/tos/%s/" % logged_in_uname:
                if not temp_user.get(
                        'agrees_with_tos', False) and config.ui.get(
                            "tos", None) is not None:
                    raise AccessDeniedException(
                        "Agree to Terms of Service before you can make any API calls."
                    )

            if requestor:
                user = None
                if ("C=" in requestor or "c=" in requestor) and dn_parser:
                    requestor_chain = [
                        dn_parser(x.replace("<", "").replace(">", ""))
                        for x in requestor.split("><")
                    ]
                    requestor_chain.reverse()
                else:
                    requestor_chain = [requestor]

                impersonator = temp_user
                merged_classification = impersonator['classification']
                for as_uname in requestor_chain:
                    user = login(as_uname)
                    if not user:
                        raise AccessDeniedException(
                            "One of the entity in the proxied "
                            "chain does not exist in our system.")
                    user[
                        'classification'] = CLASSIFICATION.intersect_user_classification(
                            user['classification'], merged_classification)
                    merged_classification = user['classification']
                    add_access_control(user)

                if user:
                    logged_in_uname = "%s(on behalf of %s)" % (
                        impersonator['uname'], user['uname'])
                else:
                    raise AccessDeniedException(
                        "Invalid proxied entities chain received.")
            else:
                impersonator = {}
                user = temp_user
            if self.require_admin and not user['is_admin']:
                raise AccessDeniedException(
                    "API %s requires ADMIN privileges" % request.path)

            #############################################
            # Special username api query validation
            #
            #    If an API call requests a username, the username as to match
            #    the logged in user or the user has to be ADMIN
            #
            #    API that needs this special validation need to make sure their
            #    variable name for the username is as an optional parameter
            #    inside 'username_key'. Default: 'username'
            if self.username_key in kwargs:
                if kwargs[self.username_key] != user['uname'] \
                        and not kwargs[self.username_key] == "__global__" \
                        and not kwargs[self.username_key] == "__workflow__" \
                        and not kwargs[self.username_key].lower() == "__current__" \
                        and not user['is_admin']:
                    return make_api_response(
                        {}, "Your username does not match requested username",
                        403)

            if self.audit:
                # noinspection PyBroadException
                try:
                    json_blob = request.json
                    if not isinstance(json_blob, dict):
                        json_blob = {}
                except Exception:
                    json_blob = {}

                params_list = list(args) + \
                    ["%s=%s" % (k, v) for k, v in kwargs.iteritems() if k in AUDIT_KW_TARGET] + \
                    ["%s=%s" % (k, v) for k, v in request.args.iteritems() if k in AUDIT_KW_TARGET] + \
                    ["%s=%s" % (k, v) for k, v in json_blob.iteritems() if k in AUDIT_KW_TARGET]

                if len(params_list) != 0:
                    AUDIT_LOG.info("%s [%s] :: %s(%s)" %
                                   (logged_in_uname, user['classification'],
                                    func.func_name, ", ".join(params_list)))

            # Save user credential in user kwarg for future reference
            kwargs['user'] = user

            # Check current user quota
            quota_user = impersonator.get('uname', None) or user['uname']
            quota_id = "%s [%s] => %s" % (quota_user, str(
                uuid.uuid4()), request.path)
            count = int(RATE_LIMITER.inc(quota_user, track_id=quota_id))
            RATE_LIMITER.inc("__global__", track_id=quota_id)

            flsk_session['quota_user'] = quota_user
            flsk_session['quota_id'] = quota_id
            flsk_session['quota_set'] = True

            quota = user.get('api_quota', 10)
            if count > quota:
                if config.ui.enforce_quota:
                    LOGGER.info(
                        "User %s was prevented from using the api due to exceeded quota. [%s/%s]"
                        % (quota_user, count, quota))
                    raise QuotaExceededException(
                        "You've exceeded your maximum quota of %s " % quota)
                else:
                    LOGGER.info("Quota exceeded for user %s. [%s/%s]" %
                                (quota_user, count, quota))
            else:
                if DEBUG:
                    LOGGER.info(
                        "%s's quota is under or equal its limit. [%s/%s]" %
                        (quota_user, count, quota))

            return func(*args, **kwargs)
Пример #7
0
        def base(*args, **kwargs):
            # Validate User-Agent
            user_agent = request.environ.get("HTTP_USER_AGENT",
                                             "Unknown browser")
            if "MSIE 8" in user_agent or "MSIE 9" in user_agent or "MSIE 7" in user_agent or "MSIE 6" in user_agent:
                return redirect(redirect_helper("/unsupported.html"))

            # Create Path
            path = request.path + "?" + request.query_string

            # Login
            try:
                session_id = flsk_session.get("session_id", None)

                if not session_id:
                    abort(401)

                session = KV_SESSION.get(session_id)

                if not session:
                    abort(401)
                else:
                    session = json.loads(session)
                    cur_time = now()
                    if session.get('expire_at', 0) < cur_time:
                        KV_SESSION.pop(session_id)
                        abort(401)
                    else:
                        session['expire_at'] = cur_time + session.get(
                            'duration', 3600)

                if request.headers.get("X-Forward-For", None) != session.get('ip', None) or \
                        request.headers.get("User-Agent", None) != session.get('user_agent', None):
                    abort(401)

                KV_SESSION.set(session_id, session)

                logged_in_uname = session.get("username", None)

                if not set(self.required_priv).intersection(
                        set(session.get("privileges", []))):
                    abort(401)

                user = login(logged_in_uname, path)
                if self.require_admin and not user['is_admin']:
                    raise AccessDeniedException(
                        "Url '%s' requires ADMIN privileges" % request.path)
            except AccessDeniedException:
                raise

            if self.audit:
                json_blob = request.json
                if not isinstance(json_blob, dict):
                    json_blob = {}
                params_list = list(args) + \
                    ["%s=%s" % (k, v) for k, v in kwargs.iteritems() if k in AUDIT_KW_TARGET] + \
                    ["%s=%s" % (k, v) for k, v in request.args.iteritems() if k in AUDIT_KW_TARGET] + \
                    ["%s=%s" % (k, v) for k, v in json_blob.iteritems() if k in AUDIT_KW_TARGET]
                AUDIT_LOG.info("%s [%s] :: %s(%s)" %
                               (logged_in_uname, user['classification'],
                                func.func_name, ", ".join(params_list)))

            # Dump Generic KWARGS
            kwargs['build_master'] = "%s.%s" % (BUILD_MASTER, BUILD_LOWER)
            kwargs['user'] = user
            kwargs['user_js'] = json.dumps(user)
            kwargs['debug'] = str(DEBUG).lower()
            kwargs['menu'] = create_menu(user, path)
            kwargs['avatar'] = STORAGE.get_user_avatar(user['uname'])
            kwargs['is_prod'] = SYSTEM_NAME == "production"
            options = STORAGE.get_user_options(user['uname'])
            if not request.path == "/terms.html":
                if not user.get('agrees_with_tos', False) and config.ui.get(
                        "tos", None) is not None:
                    return redirect(redirect_helper("/terms.html"))
                if not options and not request.path == "/settings.html":
                    return redirect(redirect_helper("/settings.html?forced"))

            if self.load_options:
                kwargs['options'] = json.dumps(options)

            kwargs["build_no"] = BUILD_NO

            return func(*args, **kwargs)