def post(self, kid): if SuperUserPermission().can(): notes = request.get_json().get("notes", "") approver = get_authenticated_user() try: key = pre_oci_model.approve_service_key( kid, approver, ServiceKeyApprovalType.SUPERUSER, notes=notes ) # Log the approval of the service key. key_log_metadata = { "kid": kid, "service": key.service, "name": key.name, "expiration_date": key.expiration_date, } log_action("service_key_approve", None, key_log_metadata) except ServiceKeyDoesNotExist: raise NotFound() except ServiceKeyAlreadyApproved: pass return make_response("", 201) raise Unauthorized()
def put(self, username): """ Updates information about the specified user. """ if SuperUserPermission().can(): user = pre_oci_model.get_nonrobot_user(username) if user is None: raise NotFound() if superusers.is_superuser(username): raise InvalidRequest('Cannot update a superuser') user_data = request.get_json() if 'password' in user_data: # Ensure that we are using database auth. if app.config['AUTHENTICATION_TYPE'] != 'Database': raise InvalidRequest( 'Cannot change password in non-database auth') pre_oci_model.change_password(username, user_data['password']) if 'email' in user_data: # Ensure that we are using database auth. if app.config['AUTHENTICATION_TYPE'] not in [ 'Database', 'AppToken' ]: raise InvalidRequest( 'Cannot change e-mail in non-database auth') pre_oci_model.update_email(username, user_data['email'], auto_verify=True) if 'enabled' in user_data: # Disable/enable the user. pre_oci_model.update_enabled(username, bool(user_data['enabled'])) if 'superuser' in user_data: config_object = config_provider.get_config() superusers_set = set(config_object['SUPER_USERS']) if user_data['superuser']: superusers_set.add(username) elif username in superusers_set: superusers_set.remove(username) config_object['SUPER_USERS'] = list(superusers_set) config_provider.save_config(config_object) return_value = user.to_dict() if user_data.get('password') is not None: password = user_data.get('password') return_value[ 'encrypted_password'] = authentication.encrypt_user_password( password) if user_data.get('email') is not None: return_value['email'] = user_data.get('email') return return_value raise Unauthorized()
def delete(self, name): """ Deletes the specified organization. """ if SuperUserPermission().can(): pre_oci_model.mark_organization_for_deletion(name) return "", 204 raise Unauthorized()
def post(self, orgname): """ Create a new organization quota. """ if not SuperUserPermission().can(): raise Unauthorized() quota_data = request.get_json() limit_bytes = quota_data["limit_bytes"] try: org = model.organization.get_organization(orgname) except model.InvalidOrganizationException: raise NotFound() # Currently only supporting one quota definition per namespace quotas = model.namespacequota.get_namespace_quota_list(orgname) if quotas: raise request_error( message="Organization quota for '%s' already exists" % orgname) try: model.namespacequota.create_namespace_quota(org, limit_bytes) return "Created", 201 except model.DataModelException as ex: raise request_error(exception=ex)
def get(self, parsed_args, page_token): """ List the usage logs for the current system. """ if SuperUserPermission().can(): start_time = parsed_args["starttime"] end_time = parsed_args["endtime"] (start_time, end_time) = _validate_logs_arguments(start_time, end_time) log_entry_page = logs_model.lookup_logs(start_time, end_time, page_token=page_token) return ( { "start_time": format_date(start_time), "end_time": format_date(end_time), "logs": [ log.to_dict(avatar, include_namespace=True) for log in log_entry_page.logs ], }, log_entry_page.next_page_token, ) raise Unauthorized()
def get(self): """ Returns the change log for this installation. """ if SuperUserPermission().can(): with open(os.path.join(ROOT_DIR, "CHANGELOG.md"), "r") as f: return {"log": f.read()} raise Unauthorized()
def get(self, parsed_args): """ Returns a list of all users in the system. """ if SuperUserPermission().can(): users = pre_oci_model.get_active_users(disabled=parsed_args["disabled"]) return {"users": [user.to_dict() for user in users]} raise Unauthorized()
def _syncing_setup_allowed(orgname): """ Returns whether syncing setup is allowed for the current user over the matching org. """ if not features.NONSUPERUSER_TEAM_SYNCING_SETUP and not SuperUserPermission( ).can(): return False return AdministerOrganizationPermission(orgname).can()
def delete(self, uuid): """ Delete a message """ if SuperUserPermission().can(): model.delete_message(uuid) return make_response("", 204) abort(403)
def post(self, orgname, quota_id): if not SuperUserPermission().can(): raise Unauthorized() quota_limit_data = request.get_json() quota_type = quota_limit_data["type"] quota_limit_threshold = quota_limit_data["threshold_percent"] quota = get_quota(orgname, quota_id) quota_limit = model.namespacequota.get_namespace_quota_limit_list( quota, quota_type=quota_type, percent_of_limit=quota_limit_threshold, ) if quota_limit: msg = "Quota limit already exists" raise request_error(message=msg) if quota_limit_data["type"].lower() == "reject" and quota_limit: raise request_error( message="Only one quota limit of type 'Reject' allowed.") try: model.namespacequota.create_namespace_quota_limit( quota, quota_type, quota_limit_threshold, ) return "Created", 201 except model.DataModelException as ex: raise request_error(exception=ex)
def post(self, namespace): """ Takes ownership of the specified organization or user. """ if SuperUserPermission().can(): # Disallow for superusers. if superusers.is_superuser(namespace): raise InvalidRequest("Cannot take ownership of a superuser") authed_user = get_authenticated_user() entity_id, was_user = pre_oci_model.take_ownership(namespace, authed_user) if entity_id is None: raise NotFound() # Log the change. log_metadata = { "entity_id": entity_id, "namespace": namespace, "was_user": was_user, "superuser": authed_user.username, } log_action("take_ownership", authed_user.username, log_metadata) return jsonify({"namespace": namespace}) raise Unauthorized()
def get(self): if SuperUserPermission().can(): keys = pre_oci_model.list_all_service_keys() return jsonify({"keys": [key.to_dict() for key in keys],}) raise Unauthorized()
def post(self): """ Creates a new user. """ # Ensure that we are using database auth. if app.config["AUTHENTICATION_TYPE"] != "Database": raise InvalidRequest("Cannot create a user in a non-database auth system") user_information = request.get_json() if SuperUserPermission().can(): # Generate a temporary password for the user. random = SystemRandom() password = "".join( [random.choice(string.ascii_uppercase + string.digits) for _ in range(32)] ) # Create the user. username = user_information["username"] email = user_information.get("email") install_user, confirmation_code = pre_oci_model.create_install_user( username, password, email ) if features.MAILING: send_confirmation_email( install_user.username, install_user.email, confirmation_code ) return { "username": username, "email": email, "password": password, "encrypted_password": authentication.encrypt_user_password(password), } raise Unauthorized()
def get(self): """ Returns a list of all organizations in the system. """ if SuperUserPermission().can(): return {"organizations": [org.to_dict() for org in pre_oci_model.get_organizations()]} raise Unauthorized()
def get(self, orgname, quota_id): orgperm = OrganizationMemberPermission(orgname) if not orgperm.can() and not SuperUserPermission().can(): raise Unauthorized() quota = get_quota(orgname, quota_id) return quota_view(quota)
def get(self, kid): if SuperUserPermission().can(): try: key = pre_oci_model.get_service_key(kid, approved_only=False, alive_only=False) return jsonify(key.to_dict()) except ServiceKeyDoesNotExist: raise NotFound() raise Unauthorized()
def put(self, name): """ Updates information about the specified user. """ if SuperUserPermission().can(): org_data = request.get_json() old_name = org_data["name"] if "name" in org_data else None org = pre_oci_model.change_organization_name(name, old_name) return org.to_dict() raise Unauthorized()
def get(self, orgname, teamname, parsed_args): """ Retrieve the list of members for the specified team. """ view_permission = ViewTeamPermission(orgname, teamname) edit_permission = AdministerOrganizationPermission(orgname) if view_permission.can(): team = None try: team = model.team.get_organization_team(orgname, teamname) except model.InvalidTeamException: raise NotFound() members = model.organization.get_organization_team_members(team.id) invites = [] if parsed_args["includePending"] and edit_permission.can(): invites = model.team.get_organization_team_member_invites( team.id) data = { "name": teamname, "members": [member_view(m) for m in members] + [invite_view(i) for i in invites], "can_edit": edit_permission.can(), } if features.TEAM_SYNCING and authentication.federated_service: if _syncing_setup_allowed(orgname): data["can_sync"] = { "service": authentication.federated_service, } data["can_sync"].update(authentication.service_metadata()) sync_info = model.team.get_team_sync_information( orgname, teamname) if sync_info is not None: data["synced"] = { "service": sync_info.service.name, } if SuperUserPermission().can(): data["synced"].update({ "last_updated": format_date(sync_info.last_updated), "config": json.loads(sync_info.config), }) return data raise Unauthorized()
def delete(self, namespace, quota_id): if SuperUserPermission().can(): namespace_user = user.get_user_or_org(namespace) quota = get_quota(namespace_user.username, quota_id) namespacequota.delete_namespace_quota(quota) return "", 204 raise Unauthorized()
def delete(self, orgname, quota_id): if not SuperUserPermission().can(): raise Unauthorized() quota = get_quota(orgname, quota_id) # Exceptions by`delete_instance` are unexpected and raised model.namespacequota.delete_namespace_quota(quota) return "", 204
def get(self, build_uuid): """ Return the status for the builds specified by the build uuids. """ if SuperUserPermission().can(): try: build = pre_oci_model.get_repository_build(build_uuid) except InvalidRepositoryBuildException as e: raise InvalidResponse(str(e)) return build.to_dict() raise Unauthorized()
def get(self, username): """ Returns information about the specified user. """ if SuperUserPermission().can(): user = pre_oci_model.get_nonrobot_user(username) if user is None: raise NotFound() return user.to_dict() raise Unauthorized()
def get(self, build_uuid): """ Return the build logs for the build specified by the build uuid. """ if SuperUserPermission().can(): try: repo_build = pre_oci_model.get_repository_build(build_uuid) return get_logs_or_log_url(repo_build) except InvalidRepositoryBuildException as e: raise InvalidResponse(str(e)) raise Unauthorized()
def get(self, parsed_args): """ Returns the aggregated logs for the current system. """ if SuperUserPermission().can(): (start_time, end_time) = _validate_logs_arguments( parsed_args["starttime"], parsed_args["endtime"] ) aggregated_logs = logs_model.get_aggregated_log_counts(start_time, end_time) return {"aggregated": [log.to_dict() for log in aggregated_logs]} raise Unauthorized()
def put(self, kid): if SuperUserPermission().can(): body = request.get_json() try: key = pre_oci_model.get_service_key(kid, approved_only=False, alive_only=False) except ServiceKeyDoesNotExist: raise NotFound() key_log_metadata = { 'kid': key.kid, 'service': key.service, 'name': body.get('name', key.name), 'expiration_date': key.expiration_date, } if 'expiration' in body: expiration_date = body['expiration'] if expiration_date is not None and expiration_date != '': try: expiration_date = datetime.utcfromtimestamp( float(expiration_date)) except ValueError as ve: raise InvalidRequest('Invalid expiration date: %s' % ve) if expiration_date <= datetime.now(): raise InvalidRequest( 'Cannot have an expiration date in the past') key_log_metadata.update({ 'old_expiration_date': key.expiration_date, 'expiration_date': expiration_date, }) log_action('service_key_extend', None, key_log_metadata) pre_oci_model.set_key_expiration(kid, expiration_date) if 'name' in body or 'metadata' in body: key_name = body.get('name') if not validate_service_key_name(key_name): raise InvalidRequest( 'Invalid service key friendly name: %s' % key_name) pre_oci_model.update_service_key(kid, key_name, body.get('metadata')) log_action('service_key_modify', None, key_log_metadata) updated_key = pre_oci_model.get_service_key(kid, approved_only=False, alive_only=False) return jsonify(updated_key.to_dict()) raise Unauthorized()
def put(self, username): """ Updates information about the specified user. """ if SuperUserPermission().can(): user = pre_oci_model.get_nonrobot_user(username) if user is None: raise NotFound() if superusers.is_superuser(username): raise InvalidRequest("Cannot update a superuser") user_data = request.get_json() if "password" in user_data: # Ensure that we are using database auth. if app.config["AUTHENTICATION_TYPE"] != "Database": raise InvalidRequest("Cannot change password in non-database auth") pre_oci_model.change_password(username, user_data["password"]) if "email" in user_data: # Ensure that we are using database auth. if app.config["AUTHENTICATION_TYPE"] not in ["Database", "AppToken"]: raise InvalidRequest("Cannot change e-mail in non-database auth") pre_oci_model.update_email(username, user_data["email"], auto_verify=True) if "enabled" in user_data: # Disable/enable the user. pre_oci_model.update_enabled(username, bool(user_data["enabled"])) if "superuser" in user_data: config_object = config_provider.get_config() superusers_set = set(config_object["SUPER_USERS"]) if user_data["superuser"]: superusers_set.add(username) elif username in superusers_set: superusers_set.remove(username) config_object["SUPER_USERS"] = list(superusers_set) config_provider.save_config(config_object) return_value = user.to_dict() if user_data.get("password") is not None: password = user_data.get("password") return_value["encrypted_password"] = authentication.encrypt_user_password( password ).decode("ascii") if user_data.get("email") is not None: return_value["email"] = user_data.get("email") return return_value raise Unauthorized()
def put(self, kid): if SuperUserPermission().can(): body = request.get_json() try: key = pre_oci_model.get_service_key(kid, approved_only=False, alive_only=False) except ServiceKeyDoesNotExist: raise NotFound() key_log_metadata = { "kid": key.kid, "service": key.service, "name": body.get("name", key.name), "expiration_date": key.expiration_date, } if "expiration" in body: expiration_date = body["expiration"] if expiration_date is not None and expiration_date != "": try: expiration_date = datetime.utcfromtimestamp( float(expiration_date)) except ValueError as ve: raise InvalidRequest("Invalid expiration date: %s" % ve) if expiration_date <= datetime.now(): raise InvalidRequest( "Cannot have an expiration date in the past") key_log_metadata.update({ "old_expiration_date": key.expiration_date, "expiration_date": expiration_date, }) log_action("service_key_extend", None, key_log_metadata) pre_oci_model.set_key_expiration(kid, expiration_date) if "name" in body or "metadata" in body: key_name = body.get("name") if not validate_service_key_name(key_name): raise InvalidRequest( "Invalid service key friendly name: %s" % key_name) pre_oci_model.update_service_key(kid, key_name, body.get("metadata")) log_action("service_key_modify", None, key_log_metadata) updated_key = pre_oci_model.get_service_key(kid, approved_only=False, alive_only=False) return jsonify(updated_key.to_dict()) raise Unauthorized()
def get(self, build_uuid): """ Returns information about a build. """ if SuperUserPermission().can(): try: build = pre_oci_model.get_repository_build(build_uuid) except InvalidRepositoryBuildException: raise NotFound() return build.to_dict() raise Unauthorized()
def calculate_overall_health(self, service_statuses, skip=None, notes=None): """ Returns true if and only if all the given service statuses report as healthy. """ is_healthy = True notes = notes or [] service_statuses_bools = {} service_status_expanded = {} for service_name in service_statuses: status, message = service_statuses[service_name] service_statuses_bools[service_name] = status service_status_expanded[service_name] = { "status": status, } if not status: service_status_expanded[service_name]["failure"] = message elif message: service_status_expanded[service_name]["message"] = message if skip and service_name in skip: notes.append("%s skipped in compute health" % service_name) continue is_healthy = is_healthy and status data = { "services": service_statuses_bools, } expanded_data = { "services_expanded": service_status_expanded, "notes": notes, "is_testing": self.app.config["TESTING"], "config_provider": self.config_provider.provider_id, "local_service_key_id": self.instance_keys.local_key_id, "hostname": socket.gethostname(), } add_debug_information = SuperUserPermission().can() or session.get( "health_debug", False) if add_debug_information: data.update(expanded_data) if not is_healthy: logger.warning("[FAILED HEALTH CHECK] %s", expanded_data) return (data, 200 if is_healthy else 503)
def calculate_overall_health(self, service_statuses, skip=None, notes=None): """ Returns true if and only if all the given service statuses report as healthy. """ is_healthy = True notes = notes or [] service_statuses_bools = {} service_status_expanded = {} for service_name in service_statuses: status, message = service_statuses[service_name] service_statuses_bools[service_name] = status service_status_expanded[service_name] = { 'status': status, } if not status: service_status_expanded[service_name]['failure'] = message elif message: service_status_expanded[service_name]['message'] = message if skip and service_name in skip: notes.append('%s skipped in compute health' % service_name) continue is_healthy = is_healthy and status data = { 'services': service_statuses_bools, } expanded_data = { 'services_expanded': service_status_expanded, 'notes': notes, 'is_testing': self.app.config['TESTING'], 'config_provider': self.config_provider.provider_id, 'local_service_key_id': self.instance_keys.local_key_id, 'hostname': socket.gethostname(), } add_debug_information = SuperUserPermission().can() or session.get( 'health_debug', False) if add_debug_information: data.update(expanded_data) if not is_healthy: logger.warning('[FAILED HEALTH CHECK] %s', expanded_data) return (data, 200 if is_healthy else 503)