def add_user_account(username, **_): """ Add a user to the system Variables: username => Name of the user to add Arguments: None Data Block: { "name": "Test user", # Name of the user "is_active": true, # Is the user active? "classification": "", # Max classification for user "uname": "usertest", # Username "is_admin": false, # Is the user admin? "avatar": null, # Avatar of the user "groups": ["TEST"] # Groups the user is member of } Result example: { "success": true # Saving the user info succeded } """ data = request.json if "{" in username or "}" in username: return make_api_response({"success": False}, "You can't use '{}' in the username", 412) if not STORAGE.get_user_account(username): new_pass = data.pop('new_pass', None) if new_pass: if not check_password_requirements( new_pass, strict=config.auth.internal.strict_requirements): if config.auth.internal.strict_requirements: error_msg = "Password needs to be 8 characters with at least an uppercase, " \ "a lowercase, a number and a special character." else: error_msg = "Password needs to be 8 alphanumeric characters." return make_api_response({"success": False}, error_msg, 469) data['password'] = get_password_hash(new_pass) STORAGE.save_user( username, validate_settings(data, ACCOUNT_DEFAULT, exceptions=[ 'avatar', 'agrees_with_tos', 'dn', 'password', 'otp_sk', 'u2f_devices' ])) return make_api_response({"success": True}) else: return make_api_response( {"success": False}, "The username you are trying to add already exists.", 400)
def list_submissions_for_user(username, **kwargs): """ List all submissions of a given user. Variables: None Arguments: offset => Offset at which we start giving submissions length => Numbers of submissions to return filter => Filter to apply to the submission list Data Block: None Result example: {"total": 201, # Total results found "offset": 0, # Offset in the result list "count": 100, # Number of results returned "items": [ # List of submissions {"submission": { # Submission Block "description": "", # Description of the submission "sid": "ad2...234", # Submission ID "groups": "GROUP", # Accessible groups "ttl": "30", # Days to live "submitter": "user", # ID of the submitter "max_score": "1422"}, # Max score of all files "times": { # Timing "submitted": # Time submitted "2014-06-17T19:20:19Z"}, "state": "completed" # State of the submission }, ... ]} """ user = kwargs['user'] offset = int(request.args.get('offset', 0)) length = int(request.args.get('length', 100)) query = request.args.get('filter', "*") account = STORAGE.get_user_account(username) if not account: return make_api_response("", "User %s does not exists." % username, 404) try: return make_api_response(STORAGE.list_submissions(username, start=offset, rows=length, qfilter=query, access_control=user['access_control'])) except RiakError, e: if e.value == "Query unsuccessful check the logs.": return make_api_response("", "The specified search query is not valid.", 400) else: raise
def get_user_account(username, **kwargs): """ Load the user account information. Variables: username => Name of the user to get the account info Arguments: load_avatar => If exists, this will load the avatar as well Data Block: None Result example: { "name": "Test user", # Name of the user "is_active": true, # Is the user active? "classification": "", # Max classification for user "uname": "usertest", # Username "is_admin": false, # Is the user admin? "avatar": null, # Avatar of the user "groups": ["TEST"] # Groups the user is member of } """ if username != kwargs['user']['uname'] and not kwargs['user']['is_admin']: return make_api_response( {}, "You are not allow to view other users then yourself.", 403) user = STORAGE.get_user_account(username) if not user: return make_api_response({}, "User %s does not exists" % username, 404) user['2fa_enabled'] = user.pop('otp_sk', None) is not None user['apikeys'] = [x[0] for x in user.get('apikeys', [])] user['has_password'] = user.pop('password', None) is not None user['u2f_enabled'] = len(user.pop('u2f_devices', [])) != 0 if "api_quota" not in user: user['api_quota'] = ACCOUNT_DEFAULT.get('api_quota', 10) if "submission_quota" not in user: user['submission_quota'] = ACCOUNT_DEFAULT.get('submission_quota', 5) if "load_avatar" in request.args: user['avatar'] = STORAGE.get_user_avatar(username) return make_api_response(user)
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)
def get_user_submission_params(username, **kwargs): """ Load the user's default submission params that should be passed to the submit API. This is mainly use so you can alter a couple fields and preserve the user default values. Variables: username => Name of the user you want to get the settings for Arguments: None Data Block: None Result example: { "profile": true, # Should submissions be profiled "classification": "", # Default classification for this user sumbissions "description": "", # Default description for this user's submissions "priority": 1000, # Default submission priority "service_spec": [], # Default Service specific parameters "ignore_cache": true, # Should file be reprocessed even if there are cached results "groups": [ ... ], # Default groups selection for the user scans "ttl": 30, # Default time to live in days of the users submissions "services": [ ... ], # Default list of selected services "ignore_tag": false, # Send file to all service even if file not supported "ignore_filtering": false # Should filtering services by ignored? } """ user = kwargs['user'] if username != "__CURRENT__" and username != user['uname']: user = STORAGE.get_user_account(username) params = load_user_settings(user) dispatch_task = ui_to_dispatch_task(params, kwargs['user']['uname']) dispatch_task['groups'] = user['groups'] return make_api_response(dispatch_task)
def get_user_settings(username, **kwargs): """ Load the user's settings. Variables: username => Name of the user you want to get the settings for Arguments: None Data Block: None Result example: { "profile": true, # Should submissions be profiled "classification": "", # Default classification for this user sumbissions "description": "", # Default description for this user's submissions "hide_raw_results": false, # Should you hide raw JSON results? "download_encoding": "blah", # Default encoding for downloaded files "expand_min_score": 100, # Default minimum score to auto-expand sections "priority": 1000, # Default submission priority "service_spec": [], # Default Service specific parameters "ignore_cache": true, # Should file be reprocessed even if there are cached results "groups": [ ... ], # Default groups selection for the user scans "ttl": 30, # Default time to live in days of the users submissions "services": [ ... ], # Default list of selected services "ignore_tag": false, # Send file to all service even if file not supported "ignore_filtering": false # Should filtering services by ignored? } """ user = kwargs['user'] if username != user['uname']: user = STORAGE.get_user_account(username) return make_api_response(load_user_settings(user))
def agree_with_tos(username, **kwargs): """ Specified user send agreement to Terms of Service Variables: username => Name of the user that agrees with tos Arguments: None Data Block: None Result example: { "success": true # Saving the user info succeded } """ logged_in_user = kwargs['user'] if logged_in_user['uname'] != username: return make_api_response( {"success": False}, "You can't agree to Terms Of Service on behalf of someone else!", 400) user = STORAGE.get_user_account(username) if not user: return make_api_response({"success": False}, "User %s does not exist." % username, 403) else: user['agrees_with_tos'] = now_as_iso() if config.ui.get('tos_lockout', False): user['is_active'] = False STORAGE.save_user(username, user) return make_api_response({"success": True})
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