Skip to content

Commit

Permalink
Merge pull request #3109 from schandrika/config_store_rpc
Browse files Browse the repository at this point in the history
Fix for config store security issue #3097
  • Loading branch information
craig8 committed Aug 26, 2023
2 parents e3f591b + fbb7de3 commit ca6fe9f
Show file tree
Hide file tree
Showing 54 changed files with 541 additions and 299 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def agent(request, volttron_instance):
test_agent = volttron_instance.build_agent()

def update_config(agent_id, name, value, cfg_type):
test_agent.vip.rpc.call('config.store', 'manage_store', agent_id, name, value, config_type=cfg_type)
test_agent.vip.rpc.call('config.store', 'set_config', agent_id, name, value, config_type=cfg_type)

capabilities = {'edit_config_store': {'identity': PLATFORM_DRIVER}}
volttron_instance.add_capabilities(test_agent.core.publickey, capabilities)
Expand All @@ -95,7 +95,7 @@ def update_config(agent_id, name, value, cfg_type):

# Build and start PlatformDriverAgent

test_agent.vip.rpc.call('config.store', 'manage_delete_store', PLATFORM_DRIVER)
test_agent.vip.rpc.call('config.store', 'delete_store', PLATFORM_DRIVER)

platform_uuid = volttron_instance.install_agent(agent_dir=get_services_core("PlatformDriverAgent"),
config_file={},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,36 +312,66 @@ Platform RPC Methods
--------------------


Methods for Agents
^^^^^^^^^^^^^^^^^^

Agent methods that change configurations do not trigger any callbacks unless trigger_callback is True.

**set_config(config_name, contents, trigger_callback=False)** - Change/create a configuration file on the platform.
**set_config(identity, config_name, contents, config_type="raw", trigger_callback=True, send_update=True)** -
Change/create a configuration on the platform for an agent with the specified identity. Requires the
authorization capability 'edit_config_store'. By default agents have access to edit only their own config store entries.

**manage_store(identity, config_name, contents, config_type="raw", trigger_callback=True, send_update=True)** -
Deprecated method. Please use set_config instead. Will be removed in VOLTTRON version 10.
Change/create a configuration on the platform for an agent with the specified identity. Requires the
authorization capability 'edit_config_store'. By default agents have access to edit only their own config store entries.

**delete_config(identity, config_name, trigger_callback=True, send_update=True)** - Delete a configuration for an
agent with the specified identity. Requires the authorization capability 'edit_config_store'. By default agents have
access to edit only their own config store entries.

**manage_delete_config(identity, config_name, trigger_callback=True, send_update=True)** -
Deprecated method. Please use delete_config instead. Will be removed in VOLTTRON version 10.
Delete a configuration for an agent with the specified identity. Requires the authorization capability
'edit_config_store'. By default agents have access to edit only their own config store entries.

**delete_store(identity)** - Delete all configurations for an agent with the specified identity. Requires the
authorization capability 'edit_config_store'. By default agents have access to edit only their own config store entries.
Calls the agent's update_config with the action `DELETE_ALL` and no configuration name.

**get_configs()** - Get all of the configurations for an Agent.
**manage_delete_store(identity)** -
Deprecated method. Please use delete_store instead. Will be removed in VOLTTRON version 10.
Delete all configurations for an agent with the specified identity. Requires the
authorization capability 'edit_config_store'. By default agents have access to edit only their own config store entries.
Calls the agent's update_config with the action `DELETE_ALL` and no configuration name.

**delete_config(config_name, trigger_callback=False)** - Delete a configuration.
**list_configs(identity)** - Get a list of configurations for an agent with the specified identity.

**manage_list_configs(identity)** -
Deprecated method. Please use list_configs instead. Will be removed in VOLTTRON version 10.
Get a list of configurations for an agent with the specified identity.

Methods for Management
^^^^^^^^^^^^^^^^^^^^^^
**list_stores()** - Get a list of all the agents with configurations.

**manage_store_config(identity, config_name, contents, config_type="raw")** - Change/create a configuration on the
platform for an agent with the specified identity
**manage_list_stores()** -
Deprecated method. Please use list_stores instead. Will be removed in VOLTTRON version 10.
Get a list of all the agents with configurations.

**manage_delete_config(identity, config_name)** - Delete a configuration for an agent with the specified identity.
Calls the agent's update_config with the action `DELETE_ALL` and no configuration name.

**manage_delete_store(identity)** - Delete all configurations for a :term:`VIP Identity`.
**get_config(identity, config_name, raw=True)** - Get the contents of a configuration file. If raw is set to
`True` this function will return the original file, otherwise it will return the parsed representation of the file.

**manage_list_config(identity)** - Get a list of configurations for an agent with the specified identity.
**manage_get_config(identity, config_name, raw=True)** -
Deprecated method. Please use get_config instead. Will be removed in VOLTTRON version 10.
Get the contents of a configuration file. If raw is set to `True` this function will return the original file,
otherwise it will return the parsed representation of the file.

**manage_get_config(identity, config_name, raw=True)** - Get the contents of a configuration file. If raw is set to
`True` this function will return the original file, otherwise it will return the parsed representation of the file.
**initialize_configs(identity)** - Called by an Agent at startup to trigger initial configuration state push.
Requires the authorization capability 'edit_config_store'. By default agents have access to edit only their own
config store entries.

**manage_list_stores()** - Get a list of all the agents with configurations.
**get_metadata(identity, config_name)** - Get the metadata of configuration named *config_name* of agent
identified by *identity*. Returns the type(json, csv, raw) of the configuration, modified date and actual content

**manage_get_metadata(identity, config_name)** -
Deprecated method. Please use get_metadata instead. Will be removed in VOLTTRON version 10.
Get the metadata of configuration named *config_name* of agent
identified by *identity*. Returns the type(json, csv, raw) of the configuration, modified date and actual content

Direct Call Methods
^^^^^^^^^^^^^^^^^^^
Expand Down
2 changes: 1 addition & 1 deletion examples/ConfigActuation/tests/test_config_actuation.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def test_thing(publish_agent):
assert value == 10.0

publish_agent.vip.rpc.call(CONFIGURATION_STORE,
"manage_store",
"set_config",
"config_actuation",
"fakedriver",
jsonapi.dumps({"SampleWritableFloat1": 42.0}),
Expand Down
6 changes: 3 additions & 3 deletions examples/ConfigActuation/update_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,21 +97,21 @@ def main():
agent = build_agent(**get_keys())

files = agent.vip.rpc.call(CONFIGURATION_STORE,
'manage_list_configs',
'list_configs',
vip_id).get(timeout=10)

if filename not in files:
config = {key: value}
else:
config = agent.vip.rpc.call(CONFIGURATION_STORE,
'manage_get',
'get_config',
vip_id,
filename).get(timeout=10)
config = jsonapi.loads(config)
config[key] = value

agent.vip.rpc.call(CONFIGURATION_STORE,
'manage_store',
'set_config',
vip_id,
filename,
jsonapi.dumps(config),
Expand Down
3 changes: 2 additions & 1 deletion requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@
'tzlocal==2.1',
#'pyOpenSSL==19.0.0',
'cryptography==37.0.4',
'watchdog-gevent==0.1.1']
'watchdog-gevent==0.1.1',
'deprecated==1.2.14']

extras_require = {'crate': ['crate==0.27.1'],
'databases': ['mysql-connector-python==8.0.30',
Expand Down
4 changes: 2 additions & 2 deletions scripts/extract_config_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def get_configs(config_id, output_directory):
event.wait()

config_list = agent.vip.rpc.call(CONFIGURATION_STORE,
'manage_list_configs',
'list_configs',
config_id).get(timeout=10)

if not config_list:
Expand All @@ -88,7 +88,7 @@ def get_configs(config_id, output_directory):
for config in config_list:
print("Retrieving configuration", config)
raw_config = agent.vip.rpc.call(CONFIGURATION_STORE,
'manage_get',
'get_config',
config_id,
config, raw=True).get(timeout=10)

Expand Down
8 changes: 4 additions & 4 deletions scripts/install_platform_driver_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,13 @@ def install_configs(input_directory, keep=False):
if not keep:
print("Deleting old Platform Driver store")
agent.vip.rpc.call(CONFIGURATION_STORE,
'manage_delete_store',
'delete_store',
PLATFORM_DRIVER).get(timeout=10)

with open("config") as f:
print("Storing main configuration")
agent.vip.rpc.call(CONFIGURATION_STORE,
'manage_store',
'set_config',
PLATFORM_DRIVER,
'config',
f.read(),
Expand All @@ -105,7 +105,7 @@ def install_configs(input_directory, keep=False):
with open(name) as f:
print("Storing configuration:", name)
agent.vip.rpc.call(CONFIGURATION_STORE,
'manage_store',
'set_config',
PLATFORM_DRIVER,
name,
f.read(),
Expand All @@ -117,7 +117,7 @@ def install_configs(input_directory, keep=False):
with open(name) as f:
print("Storing configuration:", name)
agent.vip.rpc.call(CONFIGURATION_STORE,
'manage_store',
'set_config',
PLATFORM_DRIVER,
name,
f.read(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1332,7 +1332,7 @@ def test_update_config_store(volttron_instance, influxdb_client):
publish_some_fake_data(publisher, 5)

# Update config store
publisher.vip.rpc.call('config.store', 'manage_store', 'influxdb.historian', 'config',
publisher.vip.rpc.call('config.store', 'set_config', 'influxdb.historian', 'config',
jsonapi.dumps(updated_influxdb_config), config_type="json").get(timeout=10)
publish_some_fake_data(publisher, 5)

Expand Down
2 changes: 1 addition & 1 deletion services/core/DNP3Agent/tests/test_dnp3_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def add_definitions_to_config_store(test_agent):
"""Add PointDefinitions to the mesaagent's config store."""
with open(POINT_DEFINITIONS_PATH, 'r') as f:
points_json = jsonapi.loads(strip_comments(f.read()))
test_agent.vip.rpc.call('config.store', 'manage_store', DNP3_AGENT_ID,
test_agent.vip.rpc.call('config.store', 'set_config', DNP3_AGENT_ID,
'mesa_points.config', points_json, config_type='raw')


Expand Down
4 changes: 2 additions & 2 deletions services/core/DNP3Agent/tests/test_mesa_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,11 @@ def add_definitions_to_config_store(test_agent):
"""Add PointDefinitions and FunctionDefinitions to the mesaagent's config store."""
with open(POINT_DEFINITIONS_PATH, 'r') as f:
points_json = jsonapi.loads(strip_comments(f.read()))
test_agent.vip.rpc.call('config.store', 'manage_store', MESA_AGENT_ID,
test_agent.vip.rpc.call('config.store', 'set_config', MESA_AGENT_ID,
'mesa_points.config', points_json, config_type='raw')
with open(FUNCTION_DEFINITIONS_PATH, 'r') as f:
functions_json = yaml.safe_load(f.read())
test_agent.vip.rpc.call('config.store', 'manage_store', MESA_AGENT_ID,
test_agent.vip.rpc.call('config.store', 'set_config', MESA_AGENT_ID,
'mesa_functions.config', functions_json, config_type='raw')


Expand Down
6 changes: 3 additions & 3 deletions services/core/IEEE2030_5Agent/tests/test_IEEE2030_5_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ def agent(request, volttron_instance_module_web):
capabilities = {'edit_config_store': {'identity': PLATFORM_DRIVER}}
volttron_instance_module_web.add_capabilities(test_agent.core.publickey, capabilities)
# Configure a IEEE 2030.5 device in the Platform Driver
test_agent.vip.rpc.call('config.store', 'manage_delete_store', PLATFORM_DRIVER).get(timeout=10)
test_agent.vip.rpc.call('config.store', 'manage_store', PLATFORM_DRIVER,
test_agent.vip.rpc.call('config.store', 'delete_store', PLATFORM_DRIVER).get(timeout=10)
test_agent.vip.rpc.call('config.store', 'set_config', PLATFORM_DRIVER,
'devices/{}'.format(DRIVER_NAME),
"""{
"driver_config": {
Expand All @@ -124,7 +124,7 @@ def agent(request, volttron_instance_module_web):
"heart_beat_point": "Heartbeat"
}""",
'json').get(timeout=10)
test_agent.vip.rpc.call('config.store', 'manage_store', PLATFORM_DRIVER,
test_agent.vip.rpc.call('config.store', 'set_config', PLATFORM_DRIVER,
'IEEE2030_5.csv',
REGISTRY_CONFIG_STRING,
'csv').get(timeout=10)
Expand Down
6 changes: 3 additions & 3 deletions services/core/IEEE2030_5Agent/tests/test_IEEE2030_5_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ def agent(request, volttron_instance_module_web):
test_agent = volttron_instance_module_web.build_agent()

# Configure a IEEE 2030.5 device in the Platform Driver
test_agent.vip.rpc.call('config.store', 'manage_delete_store', 'platform.driver').get(timeout=10)
test_agent.vip.rpc.call('config.store', 'manage_store', 'platform.driver',
test_agent.vip.rpc.call('config.store', 'delete_store', 'platform.driver').get(timeout=10)
test_agent.vip.rpc.call('config.store', 'set_config', 'platform.driver',
'devices/{}'.format(DRIVER_NAME),
"""{
"driver_config": {
Expand All @@ -148,7 +148,7 @@ def agent(request, volttron_instance_module_web):
"heart_beat_point": "Heartbeat"
}""",
'json').get(timeout=10)
test_agent.vip.rpc.call('config.store', 'manage_store', 'platform.driver',
test_agent.vip.rpc.call('config.store', 'set_config', 'platform.driver',
'IEEE2030_5.csv',
REGISTRY_CONFIG_STRING,
'csv').get(timeout=10)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def agent(request, volttron_instance):
md_agent = volttron_instance.build_agent()
# Clean out platform driver configurations.
md_agent.vip.rpc.call('config.store',
'manage_delete_store',
'delete_store',
'platform.driver').get(timeout=10)

driver1_config = DRIVER1_CONFIG_STRING % os.environ.get('CHARGEPOINT_PASSWORD', 'Must set a password')
Expand All @@ -166,21 +166,21 @@ def agent(request, volttron_instance):

# Add test configurations.
md_agent.vip.rpc.call('config.store',
'manage_store',
'set_config',
'platform.driver',
'devices/chargepoint1',
driver1_config,
'json').get(timeout=10)

md_agent.vip.rpc.call('config.store',
'manage_store',
'set_config',
'platform.driver',
'devices/chargepoint2',
driver2_config,
'json').get(timeout=10)

md_agent.vip.rpc.call('config.store',
'manage_store',
'set_config',
'platform.driver',
'chargepoint.csv',
REGISTRY_CONFIG_STRING,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,10 +287,10 @@ def get_auth_config_from_store(self):
:return: Fetch currently stored auth configuration info from config store, returns empty dict if none is
present
"""
configs = self.vip.rpc.call(CONFIGURATION_STORE, "manage_list_configs", PLATFORM_DRIVER).get(timeout=3)
configs = self.vip.rpc.call(CONFIGURATION_STORE, "list_configs", PLATFORM_DRIVER).get(timeout=3)
if self.auth_config_path in configs:
return jsonapi.loads(self.vip.rpc.call(
CONFIGURATION_STORE, "manage_get", PLATFORM_DRIVER, self.auth_config_path).get(timeout=3))
CONFIGURATION_STORE, "get_config", PLATFORM_DRIVER, self.auth_config_path).get(timeout=3))
else:
_log.warning("No Ecobee auth file found in config store")
return {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,27 +282,27 @@ def agent(request, volttron_instance):
# Clean out platform driver configurations
# wait for it to return before adding new config
md_agent.vip.rpc.call('config.store',
'manage_delete_store',
'delete_store',
PLATFORM_DRIVER).get()

# Add driver configurations
md_agent.vip.rpc.call('config.store',
'manage_store',
'set_config',
PLATFORM_DRIVER,
'devices/modbus_tk',
jsonapi.dumps(DRIVER_CONFIG),
config_type='json')

# Add csv configurations
md_agent.vip.rpc.call('config.store',
'manage_store',
'set_config',
PLATFORM_DRIVER,
'modbus_tk.csv',
REGISTRY_CONFIG_STRING,
config_type='csv')

md_agent.vip.rpc.call('config.store',
'manage_store',
'set_config',
PLATFORM_DRIVER,
'modbus_tk_map.csv',
REGISTER_MAP,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,27 +88,27 @@ def ion_driver_agent(request, volttron_instance):
# Clean out platform driver configurations
# wait for it to return before adding new config
md_agent.vip.rpc.call('config.store',
'manage_delete_store',
'delete_store',
PLATFORM_DRIVER).get()

# Add driver configurations
md_agent.vip.rpc.call('config.store',
'manage_store',
'set_config',
PLATFORM_DRIVER,
'devices/ion6200',
ION6200_DRIVER_CONFIG,
config_type='json')

# Add csv configurations
md_agent.vip.rpc.call('config.store',
'manage_store',
'set_config',
PLATFORM_DRIVER,
'ion6200.csv',
ION6200_CSV_CONFIG,
config_type='csv')

md_agent.vip.rpc.call('config.store',
'manage_store',
'set_config',
PLATFORM_DRIVER,
'ion6200_map.csv',
ION6200_CSV_MAP,
Expand Down

0 comments on commit ca6fe9f

Please sign in to comment.