diff --git a/sros2/sros2/api/_permission.py b/sros2/sros2/api/_permission.py index 5b590225..7e9007eb 100644 --- a/sros2/sros2/api/_permission.py +++ b/sros2/sros2/api/_permission.py @@ -34,16 +34,16 @@ def create_permission(keystore_path, identity, policy_file_path): def create_permissions_from_policy_element(keystore_path, identity, policy_element): relative_path = os.path.normpath(identity.lstrip('/')) - key_dir = os.path.join(_keystore.keystore_context_dir(keystore_path), relative_path) + key_dir = os.path.join(_keystore.get_keystore_context_dir(keystore_path), relative_path) print("creating permission file for identity: '%s'" % identity) permissions_path = os.path.join(key_dir, 'permissions.xml') create_permission_file(permissions_path, _utilities.domain_id(), policy_element) signed_permissions_path = os.path.join(key_dir, 'permissions.p7s') keystore_ca_cert_path = os.path.join( - _keystore.keystore_public_dir(keystore_path), 'ca.cert.pem') + _keystore.get_keystore_public_dir(keystore_path), 'ca.cert.pem') keystore_ca_key_path = os.path.join( - _keystore.keystore_private_dir(keystore_path), 'ca.key.pem') + _keystore.get_keystore_private_dir(keystore_path), 'ca.key.pem') _utilities.create_smime_signed_file( keystore_ca_cert_path, keystore_ca_key_path, permissions_path, signed_permissions_path) diff --git a/sros2/test/conftest.py b/sros2/test/conftest.py index 11debd4d..cc05d470 100644 --- a/sros2/test/conftest.py +++ b/sros2/test/conftest.py @@ -13,7 +13,15 @@ # limitations under the License. import os +import pathlib + +import pytest # Disable lxml2 lookup of resources on the internet by configuring it to use a proxy # that does not exist os.environ['HTTP_PROXY'] = 'http://example.com' + + +@pytest.fixture("session") +def test_policy_dir(): + return pathlib.Path(__file__).parent / 'policies' diff --git a/sros2/test/sros2/api/__init__.py b/sros2/test/sros2/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/sros2/test/sros2/commands/security/verbs/test_create_permission.py b/sros2/test/sros2/commands/security/verbs/test_create_permission.py new file mode 100644 index 00000000..05a130af --- /dev/null +++ b/sros2/test/sros2/commands/security/verbs/test_create_permission.py @@ -0,0 +1,85 @@ +# Copyright 2020 Canonical Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pathlib +import lxml + +import pytest + +from ros2cli import cli +from sros2.api import _key, _keystore + + +# This fixture will run once for the entire module (as opposed to once per test) +@pytest.fixture(scope='module') +def security_context_dir(tmpdir_factory, test_policy_dir) -> pathlib.Path: + keystore_dir = pathlib.Path(str(tmpdir_factory.mktemp('keystore'))) + + # First, create the keystore as well as a keypair for the talker + assert _keystore.create_keystore(keystore_dir) + assert _key.create_key(keystore_dir, '/talker_listener/talker') + + security_files_dir = keystore_dir / 'contexts' / 'talker_listener' / 'talker' + assert security_files_dir.is_dir() + + # Now using that keystore, create a permissions file using the sample policy + policy_file_path = test_policy_dir / 'sample.policy.xml' + assert cli.main( + argv=[ + 'security', 'create_permission', str(keystore_dir), '/talker_listener/talker', + str(policy_file_path)]) == 0 + + # Return path to directory containing the identity's files + return security_files_dir + + +def test_create_permission(security_context_dir): + assert security_context_dir.joinpath('permissions.xml').is_file() + assert security_context_dir.joinpath('permissions.p7s').is_file() + + # Give the generated permissions XML a smoke test + tree = lxml.etree.parse(str(security_context_dir.joinpath('permissions.xml'))) + + dds = tree.getroot() + assert dds.tag == 'dds' + + permissions = [c for c in dds.iterchildren(tag='permissions')] + assert len(permissions) == 1 + + grants = [c for c in permissions[0].iterchildren(tag='grant')] + assert len(grants) == 1 + assert grants[0].get("name") == '/talker_listener/talker' + + allow_rules = [c for c in grants[0].iterchildren(tag='allow_rule')] + assert len(allow_rules) == 1 + + publish_rules = [c for c in allow_rules[0].iterchildren(tag='publish')] + assert len(publish_rules) == 1 + + subscribe_rules = [c for c in allow_rules[0].iterchildren(tag='subscribe')] + assert len(subscribe_rules) == 1 + + published_topics_set = [c for c in publish_rules[0].iterchildren(tag='topics')] + assert len(published_topics_set) == 1 + published_topics = [c.text for c in published_topics_set[0].iterchildren(tag='topic')] + assert len(published_topics) == 15 + + subscribed_topics_set = [c for c in subscribe_rules[0].iterchildren(tag='topics')] + assert len(subscribed_topics_set) == 1 + subscribed_topics = [c.text for c in subscribed_topics_set[0].iterchildren(tag='topic')] + assert len(subscribed_topics) == 14 + + # Verify that publication is allowed on chatter, but not subscription + assert 'rt/chatter' in published_topics + assert 'rt/chatter' not in subscribed_topics