def create_app(): # Create a Flask instance. qflask = Flask(__name__) csrf = CSRFProtect() csrf.init_app(qflask) # Retrieve QRadar app id. qradar_app_id = qpylib.get_app_id() # Create unique session cookie name for this app. qflask.config['SESSION_COOKIE_NAME'] = 'session_{0}'.format(qradar_app_id) secret_key = "" try: # Read in secret key secret_key_store = Encryption({'name': 'secret_key', 'user': '******'}) secret_key = secret_key_store.decrypt() except EncryptionError: # If secret key file doesn't exist/fail to decrypt it, # generate a new random password for it and encrypt it secret_key = secrets.token_urlsafe(64) secret_key_store = Encryption({'name': 'secret_key', 'user': '******'}) secret_key_store.encrypt(secret_key) qflask.config["SECRET_KEY"] = secret_key # Hide server details in endpoint responses. # pylint: disable=unused-variable @qflask.after_request def obscure_server_header(resp): resp.headers['Server'] = 'QRadar App {0}'.format(qradar_app_id) return resp # Register q_url_for function for use with Jinja2 templates. qflask.add_template_global(qpylib.q_url_for, 'q_url_for') # Initialize logging. qpylib.create_log() # To enable app health checking, the QRadar App Framework # requires every Flask app to define a /debug endpoint. # The endpoint function should contain a trivial implementation # that returns a simple confirmation response message. @qflask.route('/debug') def debug(): return 'Pong!' # Import additional endpoints. # For more information see: # https://flask.palletsprojects.com/en/1.1.x/tutorial/views from . import views qflask.register_blueprint(views.viewsbp) return qflask
def test_encrypt_raises_error_when_config_db_not_writable( uuid_env_var, tmpdir): db_store = QUSER_DB_STORE db_store_path = os.path.join(tmpdir.strpath, db_store) with patch('qpylib.qpylib.get_store_path') as mock_get_store_path: mock_get_store_path.return_value = db_store_path enc = Encryption({'name': 'secret_thing', 'user': '******'}) enc.encrypt('xyz') os.chmod(db_store_path, 0o400) with pytest.raises(EncryptionError, match='Unable to save config'): enc.encrypt('xyz')
def test_encrypt_raises_error_on_encryption_failure(uuid_env_var, patch_get_store_path): enc = Encryption({'name': 'secret_thing', 'user': '******'}) enc.encrypt('mypassword') with patch('qpylib.encdec.Encryption.latest_engine_class' ) as mock_latest_engine: mock_latest_engine.return_value = DummyEngine with pytest.raises( EncryptionError, match= 'Failed to encrypt secret for name secret_thing: ValueError'): enc.encrypt('mypassword')
def test_encrypt_stores_encrypted_secret(uuid_env_var, patch_get_store_path): enc = Encryption({'name': 'secret_thing', 'user': '******'}) enc_string = enc.encrypt('testing123') assert enc_string != 'testing123' with open(QUSER_DB_STORE) as db_file: store_json = json.load(db_file) assert store_json['secret_thing']['secret'] == enc_string
def test_init_strips_leading_and_trailing_whitespace(uuid_env_var, patch_get_store_path): enc = Encryption({'name': ' secret_thing ', 'user': '******'}) enc_string = enc.encrypt('testing123') with open(QUSER_DB_STORE) as db_file: store_json = json.load(db_file) assert store_json['secret_thing']['secret'] == enc_string
def test_encryption_stores_encrypted_secret_in_config( set_unset_qradar_app_uuid_env_var, patch_get_store_path): enc = Encryption({"name": "test_name", "user": "******"}) enc_string = enc.encrypt('testing123') assert enc_string != 'testing123' with open(DB_STORE) as db_file: file_json = json.load(db_file) assert file_json.get('test_name').get('secret') == enc_string
def encrypt(key): # Get '?val=' query param value = request.args.get('val') # Encrypt the value with the key provided enc = Encryption({'name': key, 'user': '******'}) encrypted = enc.encrypt(value) return render_template('encrypt.html', key=key, value=value, encrypted=encrypted)
def test_decrypt_raises_error_when_config_missing( set_unset_qradar_app_uuid_env_var, patch_get_store_path): enc = Encryption({"name": "test_name", "user": "******"}) enc_string = enc.encrypt('testing123') assert enc_string != 'testing123' os.remove(DB_STORE) enc = Encryption({"name": "test_name", "user": "******"}) with pytest.raises(ValueError) as ex: enc.decrypt() assert str(ex.value) == "Encryption : no secret to decrypt"
def test_decrypt_returns_incorrect_plaintext_with_altered_salt( set_unset_qradar_app_uuid_env_var, patch_get_store_path): enc = Encryption({"name": "test_name", "user": "******"}) enc_string = enc.encrypt('testing123') assert enc_string != 'testing123' with open(DB_STORE) as db_file: file_json = json.load(db_file) file_json['test_name']['salt'] = 'incorrect' with open(DB_STORE, 'w') as db_file: json.dump(file_json, db_file) enc = Encryption({"name": "test_name", "user": "******"}) assert enc.decrypt() != 'testing123'
def test_decrypt_raise_value_error_on_engine_version_mismatch( set_unset_qradar_app_uuid_env_var, patch_get_store_path): enc = Encryption({"name": "test_name", "user": "******"}) enc_string = enc.encrypt('testing123') assert enc_string != 'testing123' with open(DB_STORE) as db_file: file_json = json.load(db_file) file_json['test_name']['version'] = -1 with open(DB_STORE, 'w') as db_file: json.dump(file_json, db_file) enc = Encryption({"name": "test_name", "user": "******"}) with pytest.raises(ValueError) as ex: enc.decrypt() assert "Encryption : secret engine mismatch." in str(ex.value)
def create_app(): # Create a Flask instance. qflask = Flask(__name__) csrf = CSRFProtect() csrf.init_app(qflask) # Retrieve QRadar app id. qradar_app_id = qpylib.get_app_id() # Create unique session cookie name for this app. qflask.config['SESSION_COOKIE_NAME'] = 'session_{0}'.format(qradar_app_id) secret_key = "" try: # Read in secret key secret_key_store = Encryption({'name': 'secret_key', 'user': '******'}) secret_key = secret_key_store.decrypt() except EncryptionError: # If secret key file doesn't exist/fail to decrypt it, # generate a new random password for it and encrypt it secret_key = secrets.token_urlsafe(64) secret_key_store = Encryption({'name': 'secret_key', 'user': '******'}) secret_key_store.encrypt(secret_key) qflask.config["SECRET_KEY"] = secret_key # Initialize database settings and flask configuration options via json file with open(qpylib.get_root_path( "container/conf/config.json")) as config_json_file: config_json = json.load(config_json_file) qflask.config.update(config_json) # Hide server details in endpoint responses. # pylint: disable=unused-variable @qflask.after_request def obscure_server_header(resp): resp.headers['Server'] = 'QRadar App {0}'.format(qradar_app_id) return resp # Register q_url_for function for use with Jinja2 templates. qflask.add_template_global(qpylib.q_url_for, 'q_url_for') # Initialize logging. qpylib.create_log() # To enable app health checking, the QRadar App Framework # requires every Flask app to define a /debug endpoint. # The endpoint function should contain a trivial implementation # that returns a simple confirmation response message. @qflask.route('/debug') def debug(): return 'Pong!' # Import additional endpoints. # For more information see: # https://flask.palletsprojects.com/en/1.1.x/tutorial/views from . import views qflask.register_blueprint(views.viewsbp) # NOTE: This sample app does not deal with migration of db schema between app versions as its v1.0.0. # If you have multiple versions of your application and the schema changes between them you would # need to add your own migration process at this point so that the schema is updated and loaded. # Also worth versioning your schema changes as well so you can perform the migration. db_host = qflask.config["DB_HOST"] db_port = qflask.config["DB_PORT"] db_user = qflask.config["DB_USER"] db_name = qflask.config["DB_NAME"] # create db if it doesnt exist and load schema if not db_exists(db_host, db_port, db_user, db_name): schema_file_path = qpylib.get_root_path("container/conf/db/schema.sql") create_db(db_host, db_port, db_user, db_name) execute_schema_sql(db_host, db_port, db_user, db_name, schema_file_path) return qflask
def test_encrypt_decrypt_whitespace(uuid_env_var, patch_get_store_path): enc = Encryption({'name': 'secret_thing', 'user': '******'}) assert enc.encrypt(' \n \t ') assert enc.decrypt() == ' \n \t '
def test_encrypt_decrypt_empty_string(uuid_env_var, patch_get_store_path): enc = Encryption({'name': 'secret_thing', 'user': '******'}) enc.encrypt('') assert enc.decrypt() == ''
def test_encrypt_decrypt_null_char(uuid_env_var, patch_get_store_path): enc = Encryption({'name': 'secret_thing', 'user': '******'}) enc.encrypt('\x00') assert enc.decrypt() == '\x00'
def test_decrypt_returns_original_value_after_encryption( uuid_env_var, patch_get_store_path): enc = Encryption({'name': 'secret_thing', 'user': '******'}) enc_string = enc.encrypt('testing123') assert enc_string != 'testing123' assert enc.decrypt() == 'testing123'
def test_encryption_returns_empty_string_encrypting_empty_string( set_unset_qradar_app_uuid_env_var, patch_get_store_path): enc = Encryption({"name": "test_name", "user": "******"}) assert enc.encrypt('') == ''
def test_decrypt_returns_plaintext_after_encryption( set_unset_qradar_app_uuid_env_var, patch_get_store_path): enc = Encryption({"name": "test_name", "user": "******"}) enc_string = enc.encrypt('testing123') assert enc_string != 'testing123' assert enc.decrypt() == 'testing123'