def install_plugins(app): """ Installs new issuers that are not currently bundled with Lemur. :param app: :return: """ from lemur.plugins import plugins from lemur.plugins.base import register # entry_points={ # 'lemur.plugins': [ # 'verisign = lemur_verisign.plugin:VerisignPlugin' # ], # }, for ep in pkg_resources.iter_entry_points('lemur.plugins'): try: plugin = ep.load() except Exception: import traceback app.logger.error("Failed to load plugin %r:\n%s\n" % (ep.name, traceback.format_exc())) else: register(plugin) # ensure that we have some way to notify with app.app_context(): try: slug = app.config.get("LEMUR_DEFAULT_NOTIFICATION_PLUGIN", "email-notification") plugins.get(slug) except KeyError: raise Exception("Unable to location notification plugin: {slug}. Ensure that LEMUR_DEFAULT_NOTIFICATION_PLUGIN is set to a valid and installed notification plugin.".format(slug=slug))
def install_plugins(app): """ Installs new issuers that are not currently bundled with Lemur. :param app: :return: """ from lemur.plugins import plugins from lemur.plugins.base import register # entry_points={ # 'lemur.plugins': [ # 'verisign = lemur_verisign.plugin:VerisignPlugin' # ], # }, for ep in pkg_resources.iter_entry_points('lemur.plugins'): try: plugin = ep.load() except Exception: import traceback app.logger.error("Failed to load plugin %r:\n%s\n" % (ep.name, traceback.format_exc())) else: register(plugin) # ensure that we have some way to notify with app.app_context(): try: slug = app.config.get("LEMUR_DEFAULT_NOTIFICATION_PLUGIN", "email-notification") plugins.get(slug) except KeyError: raise Exception( "Unable to location notification plugin: {slug}. Ensure that LEMUR_DEFAULT_NOTIFICATION_PLUGIN is set to a valid and installed notification plugin." .format(slug=slug))
def publish_verisign_units(): """ Simple function that queries verisign for API units and posts the mertics to Atlas API for other teams to consume. :return: """ from lemur.plugins import plugins v = plugins.get('verisign-issuer') units = v.get_available_units() metrics = {} for item in units: if item['@type'] in metrics.keys(): metrics[item['@type']] += int(item['@remaining']) else: metrics.update({item['@type']: int(item['@remaining'])}) for name, value in metrics.items(): metric = [ { "timestamp": 1321351651, "type": "GAUGE", "name": "Symantec {0} Unit Count".format(name), "tags": {}, "value": value } ] requests.post('http://localhost:8078/metrics', data=json.dumps(metric))
def send_rotation_notification(certificate, notification_plugin=None): """ Sends a report to certificate owners when their certificate has been rotated. :param certificate: :param notification_plugin: :return: """ status = FAILURE_METRIC_STATUS if not notification_plugin: notification_plugin = plugins.get(current_app.config.get('LEMUR_DEFAULT_NOTIFICATION_PLUGIN')) data = certificate_notification_output_schema.dump(certificate).data try: notification_plugin.send('rotation', data, [data['owner']]) status = SUCCESS_METRIC_STATUS except Exception as e: current_app.logger.error('Unable to send notification to {}.'.format(data['owner']), exc_info=True) sentry.captureException() metrics.send('notification', 'counter', 1, metric_tags={'status': status, 'event_type': 'rotation'}) if status == SUCCESS_METRIC_STATUS: return True
def send_rotation_notification(certificate, notification_plugin=None): """ Sends a report to certificate owners when their certificate has been rotated. :param certificate: :param notification_plugin: :return: """ status = FAILURE_METRIC_STATUS if not notification_plugin: notification_plugin = plugins.get( current_app.config.get('LEMUR_DEFAULT_NOTIFICATION_PLUGIN')) data = certificate_notification_output_schema.dump(certificate).data try: notification_plugin.send('rotation', data, [data['owner']]) status = SUCCESS_METRIC_STATUS except Exception as e: sentry.captureException() metrics.send('notification', 'counter', 1, metric_tags={ 'status': status, 'event_type': 'rotation' }) if status == SUCCESS_METRIC_STATUS: return True
def get_object(self, data, many=False): try: data['plugin_object'] = plugins.get(data['slug']) return data except Exception: raise ValidationError('Unable to find plugin: {0}'.format( data['slug']))
def send_pending_failure_notification(pending_cert, notify_owner=True, notify_security=True, notification_plugin=None): """ Sends a report to certificate owners when their pending certificate failed to be created. :param pending_cert: :param notification_plugin: :return: """ status = FAILURE_METRIC_STATUS if not notification_plugin: notification_plugin = plugins.get( current_app.config.get("LEMUR_DEFAULT_NOTIFICATION_PLUGIN", "email-notification")) data = pending_certificate_output_schema.dump(pending_cert).data data["security_email"] = current_app.config.get( "LEMUR_SECURITY_TEAM_EMAIL") if notify_owner: try: notification_plugin.send("failed", data, [data["owner"]], pending_cert) status = SUCCESS_METRIC_STATUS except Exception as e: current_app.logger.error( "Unable to send pending failure notification to {}.".format( data["owner"]), exc_info=True, ) sentry.captureException() if notify_security: try: notification_plugin.send("failed", data, data["security_email"], pending_cert) status = SUCCESS_METRIC_STATUS except Exception as e: current_app.logger.error( "Unable to send pending failure notification to " "{}.".format(data["security_email"]), exc_info=True, ) sentry.captureException() metrics.send( "notification", "counter", 1, metric_tags={ "status": status, "event_type": "rotation" }, ) if status == SUCCESS_METRIC_STATUS: return True
def publish_verisign_units(): """ Simple function that queries verisign for API units and posts the mertics to Atlas API for other teams to consume. :return: """ from lemur.plugins import plugins v = plugins.get('verisign-issuer') units = v.get_available_units() metrics = {} for item in units: if item['@type'] in metrics.keys(): metrics[item['@type']] += int(item['@remaining']) else: metrics.update({item['@type']: int(item['@remaining'])}) for name, value in metrics.items(): metric = [{ "timestamp": 1321351651, "type": "GAUGE", "name": "Symantec {0} Unit Count".format(name), "tags": {}, "value": value }] requests.post('http://localhost:8078/metrics', data=json.dumps(metric))
def send_pending_failure_notification(pending_cert, notify_owner=True, notify_security=True, notification_plugin=None): """ Sends a report to certificate owners when their pending certificate failed to be created. :param pending_cert: :param notification_plugin: :return: """ status = FAILURE_METRIC_STATUS if not notification_plugin: notification_plugin = plugins.get( current_app.config.get('LEMUR_DEFAULT_NOTIFICATION_PLUGIN', 'email-notification')) data = pending_certificate_output_schema.dump(pending_cert).data data["security_email"] = current_app.config.get( 'LEMUR_SECURITY_TEAM_EMAIL') if notify_owner: try: notification_plugin.send('failed', data, [data['owner']], pending_cert) status = SUCCESS_METRIC_STATUS except Exception as e: current_app.logger.error( 'Unable to send pending failure notification to {}.'.format( data['owner']), exc_info=True) sentry.captureException() if notify_security: try: notification_plugin.send('failed', data, data["security_email"], pending_cert) status = SUCCESS_METRIC_STATUS except Exception as e: current_app.logger.error( 'Unable to send pending failure notification to ' '{}.'.format(data['security_email']), exc_info=True) sentry.captureException() metrics.send('notification', 'counter', 1, metric_tags={ 'status': status, 'event_type': 'rotation' }) if status == SUCCESS_METRIC_STATUS: return True
def publish_unapproved_verisign_certificates(): """ Query the Verisign for any certificates that need to be approved. :return: """ from lemur.plugins import plugins from lemur.extensions import metrics v = plugins.get('verisign-issuer') certs = v.get_pending_certificates() metrics.send('pending_certificates', 'gauge', certs)
def get_object(self, data, many=False): try: data["plugin_object"] = plugins.get(data["slug"]) except KeyError as e: raise ValidationError( "Unable to find plugin. Slug: {0} Reason: {1}".format( data["slug"], e)) plugin_options_validated = [] # parse any sub-plugins for option in data.get("plugin_options", []): server_options_user_value = None if not option: continue # Angular sometimes generates empty option objects. try: option_name = option["name"] option_value = option.get("value", "") except KeyError as e: raise ValidationError( f"Unable to get plugin options. Slug: {data['slug']} Option: {option!r}" ) if "plugin" in option.get("type", []): # for plugins, sub-plugin options are validated in a recursive call to schema.load() below sub_data, errors = PluginInputSchema().load(option_value) if errors: raise ValidationError( f"Unable to load plugin options. Slug: {data['slug']} Option {option_name}" ) option["value"] = sub_data plugin_options_validated.append(option) elif data["plugin_object"]: # validate user inputs for sub-plugin options and only accept "value" field from user try: # Run regex validation rule on user input data["plugin_object"].validate_option_value( option_name, option_value) # Only accept the "value" field from the user - keep server default options for all other fields server_options_with_user_value = data[ "plugin_object"].get_server_options(option_name) if server_options_with_user_value is None: # no server options discovered plugin_options_validated.append(option) continue server_options_with_user_value["value"] = option_value plugin_options_validated.append( server_options_with_user_value) except (ValueError, ValidationError) as e: raise ValidationError( f"Unable to validate plugin options. Slug: {data['slug']} Option {option_name}: {e}" ) data["plugin_options"] = plugin_options_validated return data
def send_security_expiration_summary(exclude=None): """ Sends a report to the security team with a summary of all expiring certificates. All expiring certificates are included here, regardless of notification configuration. Certificates with notifications disabled are omitted. :param exclude: :return: """ function = f"{__name__}.{sys._getframe().f_code.co_name}" status = FAILURE_METRIC_STATUS notification_plugin = plugins.get( current_app.config.get("LEMUR_DEFAULT_NOTIFICATION_PLUGIN", "email-notification") ) notification_type = "expiration_summary" log_data = { "function": function, "message": "Sending expiration summary notification for to security team", "notification_type": notification_type, "notification_plugin": notification_plugin.slug, } intervals_and_certs = get_eligible_security_summary_certs(exclude) security_email = current_app.config.get("LEMUR_SECURITY_TEAM_EMAIL") try: current_app.logger.debug(log_data) message_data = [] for interval, certs in intervals_and_certs.items(): cert_data = [] for certificate in certs: cert_data.append(certificate_notification_output_schema.dump(certificate).data) interval_data = {"interval": interval, "certificates": cert_data} message_data.append(interval_data) notification_plugin.send(notification_type, message_data, security_email, None) status = SUCCESS_METRIC_STATUS except Exception: log_data["message"] = f"Unable to send {notification_type} notification for certificates " \ f"{intervals_and_certs} to targets {security_email}" current_app.logger.error(log_data, exc_info=True) sentry.captureException() metrics.send( "notification", "counter", 1, metric_tags={"status": status, "event_type": notification_type, "plugin": notification_plugin.slug}, ) if status == SUCCESS_METRIC_STATUS: return True
def send_default_notification(notification_type, data, targets, notification_options=None, **kwargs): """ Sends a report to the specified target via the default notification plugin. Applicable for any notification_type. At present, "default" means email, as the other notification plugins do not support dynamically configured targets. :param notification_type: :param data: :param targets: :param notification_options: :return: """ function = f"{__name__}.{sys._getframe().f_code.co_name}" status = FAILURE_METRIC_STATUS notification_plugin = plugins.get( current_app.config.get("LEMUR_DEFAULT_NOTIFICATION_PLUGIN", "email-notification")) log_data = { "function": function, "message": f"Sending {notification_type} notification for certificate data {data} to targets {targets}", "notification_type": notification_type, "notification_plugin": notification_plugin.slug, } try: current_app.logger.debug(log_data) # we need the notification.options here because the email templates utilize the interval/unit info notification_plugin.send(notification_type, data, targets, notification_options, **kwargs) status = SUCCESS_METRIC_STATUS except Exception as e: log_data["message"] = f"Unable to send {notification_type} notification for certificate data {data} " \ f"to targets {targets}" current_app.logger.error(log_data, exc_info=True) capture_exception() metrics.send( "notification", "counter", 1, metric_tags={ "status": status, "event_type": notification_type, "plugin": notification_plugin.slug }, ) if status == SUCCESS_METRIC_STATUS: return True
def get_object(self, data, many=False): try: data['plugin_object'] = plugins.get(data['slug']) # parse any sub-plugins for option in data.get('plugin_options', []): if 'plugin' in option.get('type', []): sub_data, errors = PluginInputSchema().load(option['value']) option['value'] = sub_data return data except Exception as e: raise ValidationError('Unable to find plugin. Slug: {0} Reason: {1}'.format(data['slug'], e))
def send_rotation_notification(certificate, notification_plugin=None): """ Sends a report to certificate owners when their certificate has been rotated. :param certificate: :param notification_plugin: :return: """ function = f"{__name__}.{sys._getframe().f_code.co_name}" log_data = { "function": function, "message": f"Sending rotation notification for certificate {certificate.name}", "notification_type": "rotation", "certificate_name": certificate.name, "certificate_owner": certificate.owner, } status = FAILURE_METRIC_STATUS if not notification_plugin: notification_plugin = plugins.get( current_app.config.get("LEMUR_DEFAULT_NOTIFICATION_PLUGIN", "email-notification") ) data = certificate_notification_output_schema.dump(certificate).data try: notification_plugin.send("rotation", data, [data["owner"]], []) status = SUCCESS_METRIC_STATUS except Exception as e: log_data["message"] = f"Unable to send rotation notification for certificate {certificate.name} " \ f"to owner {data['owner']}" current_app.logger.error(log_data, exc_info=True) sentry.captureException() metrics.send( "notification", "counter", 1, metric_tags={"status": status, "event_type": "rotation"}, ) if status == SUCCESS_METRIC_STATUS: return True
def send_rotation_notification(certificate, notification_plugin=None): """ Sends a report to certificate owners when their certificate as been rotated. :param certificate: :return: """ if not notification_plugin: notification_plugin = plugins.get(current_app.config.get('LEMUR_DEFAULT_NOTIFICATION_PLUGIN')) data = certificate_notification_output_schema.dump(certificate).data try: notification_plugin.send('rotation', data, [data['owner']]) metrics.send('rotation_notification_sent', 'counter', 1) return True except Exception as e: metrics.send('rotation_notification_failure', 'counter', 1) current_app.logger.exception(e)
def send_pending_failure_notification(pending_cert, notify_owner=True, notify_security=True, notification_plugin=None): """ Sends a report to certificate owners when their pending certificate failed to be created. :param pending_cert: :param notification_plugin: :return: """ status = FAILURE_METRIC_STATUS if not notification_plugin: notification_plugin = plugins.get( current_app.config.get('LEMUR_DEFAULT_NOTIFICATION_PLUGIN', 'email-notification') ) data = pending_certificate_output_schema.dump(pending_cert).data data["security_email"] = current_app.config.get('LEMUR_SECURITY_TEAM_EMAIL') if notify_owner: try: notification_plugin.send('failed', data, [data['owner']], pending_cert) status = SUCCESS_METRIC_STATUS except Exception as e: current_app.logger.error('Unable to send pending failure notification to {}.'.format(data['owner']), exc_info=True) sentry.captureException() if notify_security: try: notification_plugin.send('failed', data, data["security_email"], pending_cert) status = SUCCESS_METRIC_STATUS except Exception as e: current_app.logger.error('Unable to send pending failure notification to ' '{}.'.format(data['security_email']), exc_info=True) sentry.captureException() metrics.send('notification', 'counter', 1, metric_tags={'status': status, 'event_type': 'rotation'}) if status == SUCCESS_METRIC_STATUS: return True
def send_rotation_notification(certificate, notification_plugin=None): """ Sends a report to certificate owners when their certificate as been rotated. :param certificate: :return: """ if not notification_plugin: notification_plugin = plugins.get(current_app.config.get('LEMUR_DEFAULT_NOTIFICATION_PLUGIN')) data = certificate_notification_output_schema.dump(certificate).data try: notification_plugin.send('rotation', data, [data['owner']]) metrics.send('rotation_notification_sent', 'counter', 1) return True except Exception as e: sentry.captureException() metrics.send('rotation_notification_failure', 'counter', 1) current_app.logger.exception(e)
def send_rotation_notification(certificate, notification_plugin=None): """ Sends a report to certificate owners when their certificate has been rotated. :param certificate: :param notification_plugin: :return: """ status = FAILURE_METRIC_STATUS if not notification_plugin: notification_plugin = plugins.get( current_app.config.get("LEMUR_DEFAULT_NOTIFICATION_PLUGIN")) data = certificate_notification_output_schema.dump(certificate).data try: notification_plugin.send("rotation", data, [data["owner"]]) status = SUCCESS_METRIC_STATUS except Exception as e: current_app.logger.error("Unable to send notification to {}.".format( data["owner"]), exc_info=True) sentry.captureException() metrics.send( "notification", "counter", 1, metric_tags={ "status": status, "event_type": "rotation" }, ) if status == SUCCESS_METRIC_STATUS: return True
def get_object(self, data, many=False): try: data['plugin_object'] = plugins.get(data['slug']) return data except Exception: raise ValidationError('Unable to find plugin: {0}'.format(data['slug']))
def post(self, certificate_id): """ .. http:post:: /certificates/1/export Export a certificate **Example request**: .. sourcecode:: http PUT /certificates/1/export HTTP/1.1 Host: example.com Accept: application/json, text/javascript { "export": { "plugin": { "pluginOptions": [{ "available": ["Java Key Store (JKS)"], "required": true, "type": "select", "name": "type", "helpMessage": "Choose the format you wish to export", "value": "Java Key Store (JKS)" }, { "required": false, "type": "str", "name": "passphrase", "validation": "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[$@$!%*#?&])[A-Za-z\\d$@$!%*#?&]{8,}$", "helpMessage": "If no passphrase is given one will be generated for you, we highly recommend this. Minimum length is 8." }, { "required": false, "type": "str", "name": "alias", "helpMessage": "Enter the alias you wish to use for the keystore." }], "version": "unknown", "description": "Attempts to generate a JKS keystore or truststore", "title": "Java", "author": "Kevin Glisson", "type": "export", "slug": "java-export" } } } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: text/javascript { "data": "base64encodedstring", "passphrase": "UAWOHW#&@_%!tnwmxh832025", "extension": "jks" } :reqheader Authorization: OAuth token to authenticate :statuscode 200: no error :statuscode 403: unauthenticated """ self.reqparse.add_argument('export', type=dict, required=True, location='json') args = self.reqparse.parse_args() cert = service.get(certificate_id) role = role_service.get_by_name(cert.owner) permission = UpdateCertificatePermission(certificate_id, getattr(role, 'name', None)) plugin = plugins.get(args['export']['plugin']['slug']) if plugin.requires_key: if permission.can(): extension, passphrase, data = plugin.export(cert.body, cert.chain, cert.private_key, args['export']['plugin']['pluginOptions']) else: return dict(message='You are not authorized to export this certificate'), 403 else: extension, passphrase, data = plugin.export(cert.body, cert.chain, cert.private_key, args['export']['plugin']['pluginOptions']) # we take a hit in message size when b64 encoding return dict(extension=extension, passphrase=passphrase, data=base64.b64encode(data))
def upload_acme_token_s3(token, token_name, prefix, account_number, bucket_name): """ This method serves for testing the upload_acme_token to S3, fetching the token to verify it, and then deleting it. It mainly serves for testing purposes. :param token: :param token_name: :param prefix: :param account_number: :param bucket_name: :return: """ additional_options = [ { "name": "bucket", "value": bucket_name, "type": "str", "required": True, "validation": r"[0-9a-z.-]{3,63}", "helpMessage": "Must be a valid S3 bucket name!", }, { "name": "accountNumber", "type": "str", "value": account_number, "required": True, "validation": r"[0-9]{12}", "helpMessage": "A valid AWS account number with permission to access S3", }, { "name": "region", "type": "str", "default": "us-east-1", "required": False, "helpMessage": "Region bucket exists", "available": ["us-east-1", "us-west-2", "eu-west-1"], }, { "name": "encrypt", "type": "bool", "value": False, "required": False, "helpMessage": "Enable server side encryption", "default": True, }, { "name": "prefix", "type": "str", "value": prefix, "required": False, "helpMessage": "Must be a valid S3 object prefix!", }, ] p = plugins.get("aws-s3") p.upload_acme_token(token_name, token, additional_options) if not prefix.endswith("/"): prefix + "/" token_res = s3.get(bucket_name, prefix + token_name, account_number=account_number) assert (token_res == token) s3.delete(bucket_name, prefix + token_name, account_number=account_number)
def get_object(self, data, many=False): if many: return [plugins.get(plugin['slug']) for plugin in data] else: return plugins.get(data['slug'])
def post(self, certificate_id): """ .. http:post:: /certificates/1/export Export a certificate **Example request**: .. sourcecode:: http PUT /certificates/1/export HTTP/1.1 Host: example.com Accept: application/json, text/javascript { "export": { "plugin": { "pluginOptions": [{ "available": ["Java Key Store (JKS)"], "required": true, "type": "select", "name": "type", "helpMessage": "Choose the format you wish to export", "value": "Java Key Store (JKS)" }, { "required": false, "type": "str", "name": "passphrase", "validation": "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[$@$!%*#?&])[A-Za-z\\d$@$!%*#?&]{8,}$", "helpMessage": "If no passphrase is given one will be generated for you, we highly recommend this. Minimum length is 8." }, { "required": false, "type": "str", "name": "alias", "helpMessage": "Enter the alias you wish to use for the keystore." }], "version": "unknown", "description": "Attempts to generate a JKS keystore or truststore", "title": "Java", "author": "Kevin Glisson", "type": "export", "slug": "java-export" } } } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: text/javascript { "data": "base64encodedstring", "passphrase": "UAWOHW#&@_%!tnwmxh832025", "extension": "jks" } :reqheader Authorization: OAuth token to authenticate :statuscode 200: no error :statuscode 403: unauthenticated """ self.reqparse.add_argument('export', type=dict, required=True, location='json') args = self.reqparse.parse_args() cert = service.get(certificate_id) role = role_service.get_by_name(cert.owner) permission = UpdateCertificatePermission(certificate_id, getattr(role, 'name', None)) plugin = plugins.get(args['export']['plugin']['slug']) if plugin.requires_key: if permission.can(): extension, passphrase, data = plugin.export( cert.body, cert.chain, cert.private_key, args['export']['plugin']['pluginOptions']) else: return dict( message='You are not authorized to export this certificate' ), 403 else: extension, passphrase, data = plugin.export( cert.body, cert.chain, cert.private_key, args['export']['plugin']['pluginOptions']) # we take a hit in message size when b64 encoding return dict(extension=extension, passphrase=passphrase, data=base64.b64encode(data))
def get_object(self, data, many=False): data['plugin_object'] = plugins.get(data['slug']) return data
def send_pending_failure_notification( pending_cert, notify_owner=True, notify_security=True, notification_plugin=None ): """ Sends a report to certificate owners when their pending certificate failed to be created. :param pending_cert: :param notification_plugin: :return: """ function = f"{__name__}.{sys._getframe().f_code.co_name}" log_data = { "function": function, "message": f"Sending pending failure notification for pending certificate {pending_cert}", "notification_type": "failed", "certificate_name": pending_cert.name, "certificate_owner": pending_cert.owner, } status = FAILURE_METRIC_STATUS if not notification_plugin: notification_plugin = plugins.get( current_app.config.get( "LEMUR_DEFAULT_NOTIFICATION_PLUGIN", "email-notification" ) ) data = pending_certificate_output_schema.dump(pending_cert).data data["security_email"] = current_app.config.get("LEMUR_SECURITY_TEAM_EMAIL") if notify_owner: try: notification_plugin.send("failed", data, [data["owner"]], pending_cert) status = SUCCESS_METRIC_STATUS except Exception as e: log_data["recipient"] = data["owner"] log_data["message"] = f"Unable to send pending failure notification for certificate {pending_cert.name} " \ f"to owner {pending_cert.owner}" current_app.logger.error(log_data, exc_info=True) sentry.captureException() if notify_security: try: notification_plugin.send( "failed", data, data["security_email"], pending_cert ) status = SUCCESS_METRIC_STATUS except Exception as e: log_data["recipient"] = data["security_email"] log_data["message"] = f"Unable to send pending failure notification for certificate {pending_cert.name} " \ f"to security email {pending_cert.owner}" current_app.logger.error(log_data, exc_info=True) sentry.captureException() metrics.send( "notification", "counter", 1, metric_tags={"status": status, "event_type": "failed"}, ) if status == SUCCESS_METRIC_STATUS: return True