async def get(self) -> None: """ Get the dynamic configuration endpoint. --- description: Presents a YAML-configured editor to allow viewing and modification of dynamic config responses: 200: description: View of dynamic configuration 403: description: Unauthorized to access this page """ if not self.user: return if not can_edit_dynamic_config(self.user, self.groups): raise tornado.web.HTTPError( 403, "Only application admins are authorized to view this page.") dynamic_config = await ddb.get_dynamic_config_yaml() self.write({ "dynamicConfig": dynamic_config.decode("utf-8"), "sha256": sha256(dynamic_config).hexdigest(), })
async def get(self): """ Provide information about site configuration for the frontend :return: """ is_contractor = config.config_plugin().is_contractor(self.user) site_config = { "consoleme_logo": await get_random_security_logo(), "google_tracking_uri": config.get("google_analytics.tracking_url"), "documentation_url": config.get("documentation_page"), "support_contact": config.get("support_contact"), "support_chat_url": config.get("support_chat_url"), "security_logo": config.get("security_logo.image"), "security_url": config.get("security_logo.url"), } user_profile = { "site_config": site_config, "user": self.user, "can_logout": config.get("auth.set_auth_cookie"), "is_contractor": is_contractor, "employee_photo_url": config.config_plugin().get_employee_photo_url(self.user), "employee_info_url": config.config_plugin().get_employee_info_url(self.user), "authorization": { "can_edit_policies": can_admin_policies(self.user, self.groups), "can_create_roles": can_create_roles(self.user, self.groups), "can_delete_roles": can_delete_roles(self.user, self.groups), }, "pages": { "header": { "custom_header_message_title": config.get("headers.custom_header_message.title", ""), "custom_header_message_text": config.get("headers.custom_header_message.text", ""), }, "groups": { "enabled": config.get("headers.group_access.enabled", False) }, "users": { "enabled": config.get("headers.group_access.enabled", False) }, "policies": { "enabled": config.get("headers.policies.enabled", True) and not is_contractor }, "self_service": { "enabled": config.get("enable_self_service", True) and not is_contractor }, "api_health": { "enabled": is_in_group( self.user, self.groups, config.get("groups.can_edit_health_alert", []), ) }, "audit": { "enabled": is_in_group(self.user, self.groups, config.get("groups.can_audit", [])) }, "config": { "enabled": can_edit_dynamic_config(self.user, self.groups) }, }, "accounts": await get_account_id_to_name_mapping(), } self.set_header("Content-Type", "application/json") self.write(user_profile)
async def get(self): """ Provide information about site configuration for the frontend :return: """ is_contractor = config.config_plugin().is_contractor(self.user) site_config = { "consoleme_logo": await get_random_security_logo(), "google_analytics": { "tracking_id": config.get("google_analytics.tracking_id"), "options": config.get("google_analytics.options", {}), }, "documentation_url": config.get( "documentation_page", "https://hawkins.gitbook.io/consoleme/" ), "support_contact": config.get("support_contact"), "support_chat_url": config.get( "support_chat_url", "https://discord.com/invite/nQVpNGGkYu" ), "security_logo": config.get("security_logo.image"), "security_url": config.get("security_logo.url"), # If site_config.landing_url is set, users will be redirected to the landing URL after authenticating # on the frontend. "landing_url": config.get("site_config.landing_url"), "temp_policy_support": config.get("policies.temp_policy_support"), "notifications": { "enabled": config.get("site_config.notifications.enabled"), "request_interval": config.get( "site_config.notifications.request_interval", 60 ), }, "cloudtrail_denies_policy_generation": config.get( "celery.cache_cloudtrail_denies.enabled", False ), } custom_page_header: Dict[str, str] = await get_custom_page_header( self.user, self.groups ) user_profile = { "site_config": site_config, "user": self.user, "can_logout": config.get("auth.set_auth_cookie", False), "is_contractor": is_contractor, "employee_photo_url": config.config_plugin().get_employee_photo_url( self.user ), "employee_info_url": config.config_plugin().get_employee_info_url( self.user ), "authorization": { "can_edit_policies": can_admin_policies(self.user, self.groups), "can_create_roles": can_create_roles(self.user, self.groups), "can_delete_iam_principals": can_delete_iam_principals( self.user, self.groups ), }, "pages": { "header": { "custom_header_message_title": custom_page_header.get( "custom_header_message_title", "" ), "custom_header_message_text": custom_page_header.get( "custom_header_message_text", "" ), "custom_header_message_route": custom_page_header.get( "custom_header_message_route", "" ), }, "groups": { "enabled": config.get("headers.group_access.enabled", False) }, "users": {"enabled": config.get("headers.group_access.enabled", False)}, "policies": { "enabled": config.get("headers.policies.enabled", True) and not is_contractor }, "self_service": { "enabled": config.get("enable_self_service", True) and not is_contractor }, "api_health": { "enabled": is_in_group( self.user, self.groups, config.get("groups.can_edit_health_alert", []), ) }, "audit": { "enabled": is_in_group( self.user, self.groups, config.get("groups.can_audit", []) ) }, "config": {"enabled": can_edit_dynamic_config(self.user, self.groups)}, }, "accounts": await get_account_id_to_name_mapping(), } self.set_header("Content-Type", "application/json") self.write(user_profile)
async def post(self): """ Post an update to the dynamic configuration endpoint. --- description: Update dynamic configuration responses: 200: description: Update successful. 403: description: Unauthorized to access this page """ if not self.user: return if not can_edit_dynamic_config(self.user, self.groups): raise tornado.web.HTTPError( 403, "Only application admins are authorized to view this page.") existing_dynamic_config = await ddb.get_dynamic_config_yaml() if existing_dynamic_config: existing_dynamic_config_sha256 = sha256( existing_dynamic_config).hexdigest() else: existing_dynamic_config_sha256 = None result = {"status": "success"} log_data = { "function": f"{__name__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}", "user": self.user, "existing_dynamic_config_sha256": existing_dynamic_config_sha256, } log.debug(log_data) data = tornado.escape.json_decode(self.request.body) try: existing_sha256 = data.get("existing_sha256") new_sha256 = sha256(data["new_config"].encode("utf-8")).hexdigest() if existing_sha256 == new_sha256: raise Exception( "You didn't change the dynamic configuration. Try again!") if (existing_dynamic_config_sha256 and not existing_dynamic_config_sha256 == existing_sha256): raise Exception( "Dynamic configuration was updated by another user before your changes were processed. " "Please refresh your page and try again.") await ddb.update_dynamic_config(data["new_config"], self.user) except Exception as e: result["status"] = "error" result[ "error"] = f"There was an error processing your request: {e}" sentry_sdk.capture_exception() self.write(json.dumps(result, cls=SetEncoder)) await self.finish() return result["newConfig"] = data["new_config"] result["newsha56"] = new_sha256 self.write(result) await self.finish() return