diff --git a/app/models.py b/app/models.py index 0da30ba3ccdcc0654900bfb811fefc6fa0f348ce..68d4577d80328404c179edecbbed67989fcaf7b1 100644 --- a/app/models.py +++ b/app/models.py @@ -221,10 +221,10 @@ class User(db.Model, UserMixin): ].items(): if set(self.groups) & set(ldap_groups): self._csentry_groups.append(csentry_group) - # Add the network group based on CSENTRY_DOMAINS_LDAP_GROUPS + # Add the network group based on CSENTRY_NETWORK_SCOPES_LDAP_GROUPS network_ldap_groups = set( itertools.chain( - *current_app.config["CSENTRY_DOMAINS_LDAP_GROUPS"].values() + *current_app.config["CSENTRY_NETWORK_SCOPES_LDAP_GROUPS"].values() ) ) if set(self.groups) & network_ldap_groups: @@ -232,19 +232,19 @@ class User(db.Model, UserMixin): return self._csentry_groups @property - def csentry_domains(self): - """Return the list of CSEntry domains the user has access to + def csentry_network_scopes(self): + """Return the list of CSEntry network scopes the user has access to - Domains are assigned based on the CSENTRY_DOMAINS_LDAP_GROUPS mapping with LDAP groups + Network scopes are assigned based on the CSENTRY_NETWORK_SCOPES_LDAP_GROUPS mapping with LDAP groups """ - if not hasattr(self, "_csentry_domains"): - self._csentry_domains = [] - for domain, ldap_groups in current_app.config[ - "CSENTRY_DOMAINS_LDAP_GROUPS" + if not hasattr(self, "_csentry_network_scopes"): + self._csentry_network_scopes = [] + for network_scope, ldap_groups in current_app.config[ + "CSENTRY_NETWORK_SCOPES_LDAP_GROUPS" ].items(): if set(self.groups) & set(ldap_groups): - self._csentry_domains.append(domain) - return self._csentry_domains + self._csentry_network_scopes.append(network_scope) + return self._csentry_network_scopes @property def is_admin(self): @@ -258,8 +258,8 @@ class User(db.Model, UserMixin): """Return True if the user has access to the network - admin users have access to all networks - - normal users must have access to the network domain - - normal users don't have access to admin_only networks (whatever the domain) + - normal users must have access to the network scope + - normal users don't have access to admin_only networks (whatever the network scope) - LOGIN_DISABLED can be set to True to turn off authentication check when testing. In this case, this function always returns True. """ @@ -268,7 +268,7 @@ class User(db.Model, UserMixin): if network is None or network.admin_only: # True is already returned for admin users return False - return str(network.domain) in self.csentry_domains + return str(network.scope) in self.csentry_network_scopes def can_create_vm(self, host): """Return True if the user can create the VM @@ -276,7 +276,7 @@ class User(db.Model, UserMixin): - host.device_type shall be VirtualMachine - admin users can create anything - normal users must have access to the network to create VIOC - - normal users can only create a VM if the host is in one of the allowed domains + - normal users can only create a VM if the host is in one of the allowed network scopes - LOGIN_DISABLED can be set to True to turn off authentication check when testing. In this case, this function always returns True. """ @@ -290,10 +290,10 @@ class User(db.Model, UserMixin): if host.is_ioc: # VIOC can be created by anyone having access to the network return True - # VM can only be created if the domain is allowed + # VM can only be created if the network scope is allowed return ( - str(host.main_interface.network.domain) - in current_app.config["ALLOWED_VM_CREATION_DOMAINS"] + str(host.main_interface.network.scope) + in current_app.config["ALLOWED_VM_CREATION_NETWORK_SCOPES"] ) def can_set_boot_profile(self, host): @@ -302,7 +302,7 @@ class User(db.Model, UserMixin): - host.device_type shall be PhysicalMachine - admin users can always set the profile - normal users must have access to the network - - normal users can only set the boot profile if the host is in one of the allowed domains + - normal users can only set the boot profile if the host is in one of the allowed network scopes - LOGIN_DISABLED can be set to True to turn off authentication check when testing. In this case, this function always returns True. """ @@ -313,10 +313,10 @@ class User(db.Model, UserMixin): if not self.has_access_to_network(host.main_network): # True is already returned for admin users return False - # Boot profile can only be set if the domain is allowed + # Boot profile can only be set if the network scope is allowed return ( - str(host.main_interface.network.domain) - in current_app.config["ALLOWED_SET_BOOT_PROFILE_DOMAINS"] + str(host.main_interface.network.scope) + in current_app.config["ALLOWED_SET_BOOT_PROFILE_NETWORK_SCOPES"] ) def can_delete_host(self, host): diff --git a/app/settings.py b/app/settings.py index 625938efc5e382776775cf8884ecd85b97c42db5..3e28eb4d704a933bef11cba210819df08ad0dfde 100644 --- a/app/settings.py +++ b/app/settings.py @@ -60,21 +60,21 @@ LDAP_GET_GROUP_ATTRIBUTES = ["cn"] # Mapping between CSEntry groups and LDAP groups # The generic "network" group is automatically added based -# on all CSENTRY_DOMAINS_LDAP_GROUPS +# on all CSENTRY_NETWORK_SCOPES_LDAP_GROUPS CSENTRY_LDAP_GROUPS = { "admin": ["ICS Control System Infrastructure group"], "inventory": ["ICS Employees", "ICS Consultants"], } -# Domains the user has access to based on LDAP groups -CSENTRY_DOMAINS_LDAP_GROUPS = { - "esss.lu.se": ["ICS Control System Infrastructure group"], - "tn.esss.lu.se": ["ICS Employees", "ICS Consultants"], - "cslab.esss.lu.se": ["ICS Employees", "ICS Consultants"], +# Network scopes the user has access to based on LDAP groups +# Admin users have access to all network scopes (even if not defined here) +CSENTRY_NETWORK_SCOPES_LDAP_GROUPS = { + "TechnicalNetwork": ["ICS Employees", "ICS Consultants"], + "LabNetworks": ["ICS Employees", "ICS Consultants"], } -# List of domains where users can create a VM -ALLOWED_VM_CREATION_DOMAINS = ["cslab.esss.lu.se"] -# List of domains where users can set the boot profile for physical machines -ALLOWED_SET_BOOT_PROFILE_DOMAINS = ["cslab.esss.lu.se"] +# List of network scopes where users can create a VM +ALLOWED_VM_CREATION_NETWORK_SCOPES = ["LabNetworks"] +# List of network scopes where users can set the boot profile for physical machines +ALLOWED_SET_BOOT_PROFILE_NETWORK_SCOPES = ["LabNetworks"] # List of existing boot profiles # Shall be kept in sync with the ics-ans-role-autoinstall Ansible role AUTOINSTALL_BOOT_PROFILES = ["localboot", "default", "cct", "LCR", "thinclient"] diff --git a/app/templates/user/profile.html b/app/templates/user/profile.html index 479c0ae52b1cf68bc9d043dc01510ffd02cf6cf6..14b58be1ced43de80930059054421c76a28e1dcf 100644 --- a/app/templates/user/profile.html +++ b/app/templates/user/profile.html @@ -27,8 +27,8 @@ <dd>{{user.email}}</dd> <dt>CSEntry Groups</dt> <dd>{{ user.csentry_groups | join(', ') }}</dd> - <dt>CSEntry Domains</dt> - <dd>{{ user.csentry_domains | join(', ') }}</dd> + <dt>CSEntry Network Scopes</dt> + <dd>{{ user.csentry_network_scopes | join(', ') }}</dd> </dl> <h3>Personal access tokens</h3> diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py index 1504e4fb9ffdd862a1460c3964e3261d220899fa..ad80244d7e391930fdfe2629719e641f7638cb6f 100644 --- a/tests/functional/conftest.py +++ b/tests/functional/conftest.py @@ -53,14 +53,14 @@ def app(request): "admin": ["CSEntry Admin"], "inventory": ["CSEntry User"], }, - "CSENTRY_DOMAINS_LDAP_GROUPS": { - "prod.example.org": ["CSEntry Prod"], - "lab.example.org": ["CSEntry Lab"], - "foo.example.org": ["CSEntry User", "CSEntry Consultant"], + "CSENTRY_NETWORK_SCOPES_LDAP_GROUPS": { + "ProdNetworks": ["CSEntry Prod"], + "LabNetworks": ["CSEntry Lab"], + "FooNetworks": ["CSEntry User", "CSEntry Consultant"], }, "AWX_URL": "https://awx.example.org", - "ALLOWED_VM_CREATION_DOMAINS": ["lab.example.org"], - "ALLOWED_SET_BOOT_PROFILE_DOMAINS": ["lab.example.org"], + "ALLOWED_VM_CREATION_NETWORK_SCOPES": ["LabNetworks"], + "ALLOWED_SET_BOOT_PROFILE_NETWORK_SCOPES": ["LabNetworks"], "MAX_PER_PAGE": 25, } app = create_app(config=config) diff --git a/tests/functional/test_models.py b/tests/functional/test_models.py index 05c93dc60263532ef2b9e056b753c1c2e66127dd..39652135b1174160face218be9247a5ebcab552f 100644 --- a/tests/functional/test_models.py +++ b/tests/functional/test_models.py @@ -44,19 +44,21 @@ def test_user_is_member_of_one_group(user_factory): assert user.is_member_of_one_group(["admin"]) -def test_user_domains(user_factory): +def test_user_network_scopes(user_factory): user = user_factory(groups=["CSEntry Prod", "CSEntry User"]) - assert user.csentry_domains == ["prod.example.org", "foo.example.org"] + assert user.csentry_network_scopes == ["ProdNetworks", "FooNetworks"] user = user_factory(groups=["foo", "CSEntry Lab"]) - assert user.csentry_domains == ["lab.example.org"] + assert user.csentry_network_scopes == ["LabNetworks"] -def test_user_has_access_to_network(user_factory, domain_factory, network_factory): - domain_prod = domain_factory(name="prod.example.org") - domain_lab = domain_factory(name="lab.example.org") - network_prod = network_factory(domain=domain_prod) - network_lab = network_factory(domain=domain_lab) - network_lab_admin = network_factory(domain=domain_lab, admin_only=True) +def test_user_has_access_to_network( + user_factory, network_scope_factory, network_factory +): + scope_prod = network_scope_factory(name="ProdNetworks") + scope_lab = network_scope_factory(name="LabNetworks") + network_prod = network_factory(scope=scope_prod) + network_lab = network_factory(scope=scope_lab) + network_lab_admin = network_factory(scope=scope_lab, admin_only=True) user = user_factory(groups=["CSEntry Prod", "CSEntry Lab"]) assert user.has_access_to_network(network_prod) assert user.has_access_to_network(network_lab) @@ -79,18 +81,18 @@ def test_user_has_access_to_network(user_factory, domain_factory, network_factor def test_user_can_create_vm( user_factory, - domain_factory, + network_scope_factory, network_factory, device_type_factory, host_factory, interface_factory, ): virtualmachine = device_type_factory(name="VirtualMachine") - domain_prod = domain_factory(name="prod.example.org") - domain_lab = domain_factory(name="lab.example.org") - network_prod = network_factory(domain=domain_prod) - network_lab = network_factory(domain=domain_lab) - network_lab_admin = network_factory(domain=domain_lab, admin_only=True) + scope_prod = network_scope_factory(name="ProdNetworks") + scope_lab = network_scope_factory(name="LabNetworks") + network_prod = network_factory(scope=scope_prod) + network_lab = network_factory(scope=scope_lab) + network_lab_admin = network_factory(scope=scope_lab, admin_only=True) vm_prod = host_factory(device_type=virtualmachine) interface_factory(name=vm_prod.name, host=vm_prod, network=network_prod) vioc_prod = host_factory(device_type=virtualmachine, is_ioc=True) @@ -112,7 +114,7 @@ def test_user_can_create_vm( interface_factory(name=non_vm.name, host=non_vm, network=network_lab) interface_factory(name=non_vm_ioc.name, host=non_vm_ioc, network=network_lab) # User has access to prod and lab networks but can only create a VM in the lab - # (due to ALLOWED_VM_CREATION_DOMAINS) and VIOC in both + # (due to ALLOWED_VM_CREATION_NETWORK_SCOPES) and VIOC in both user = user_factory(groups=["CSEntry Prod", "CSEntry Lab"]) assert user.can_create_vm(vm_lab) assert not user.can_create_vm(vm_prod) @@ -156,18 +158,18 @@ def test_user_can_create_vm( def test_user_can_set_boot_profile( user_factory, - domain_factory, + network_scope_factory, network_factory, device_type_factory, host_factory, interface_factory, ): physicalmachine = device_type_factory(name="PhysicalMachine") - domain_prod = domain_factory(name="prod.example.org") - domain_lab = domain_factory(name="lab.example.org") - network_prod = network_factory(domain=domain_prod) - network_lab = network_factory(domain=domain_lab) - network_lab_admin = network_factory(domain=domain_lab, admin_only=True) + scope_prod = network_scope_factory(name="ProdNetworks") + scope_lab = network_scope_factory(name="LabNetworks") + network_prod = network_factory(scope=scope_prod) + network_lab = network_factory(scope=scope_lab) + network_lab_admin = network_factory(scope=scope_lab, admin_only=True) server_prod = host_factory(device_type=physicalmachine) interface_factory(name=server_prod.name, host=server_prod, network=network_prod) ioc_prod = host_factory(device_type=physicalmachine, is_ioc=True) @@ -191,7 +193,7 @@ def test_user_can_set_boot_profile( name=non_physical_ioc.name, host=non_physical_ioc, network=network_lab ) # User has access to prod and lab networks but can only set the boot profile in the lab - # (due to ALLOWED_SET_BOOT_PROFILE_DOMAINS) + # (due to ALLOWED_SET_BOOT_PROFILE_NETWORK_SCOPES) user = user_factory(groups=["CSEntry Prod", "CSEntry Lab"]) assert user.can_set_boot_profile(server_lab) assert not user.can_set_boot_profile(server_prod) diff --git a/tests/functional/test_web.py b/tests/functional/test_web.py index 5907be5d9a318f7de209ca7650b331ffe8dca9f1..4204ac909c5a35fb206e99b9e57c4d540ed93a34 100644 --- a/tests/functional/test_web.py +++ b/tests/functional/test_web.py @@ -299,13 +299,13 @@ def test_edit_item_comment_in_index( assert list(instances) == [item1] -def test_create_host(client, domain_factory, network_factory, device_type): - domain = domain_factory(name="prod.example.org") +def test_create_host(client, network_scope_factory, network_factory, device_type): + scope = network_scope_factory(name="ProdNetworks") network = network_factory( address="192.168.1.0/24", first_ip="192.168.1.10", last_ip="192.168.1.250", - domain=domain, + scope=scope, ) name = "myhost" ip = "192.168.1.11" @@ -347,14 +347,14 @@ def test_create_host(client, domain_factory, network_factory, device_type): def test_create_host_invalid_fields( - session, client, domain_factory, network_factory, device_type + session, client, network_scope_factory, network_factory, device_type ): - domain = domain_factory(name="prod.example.org") + scope = network_scope_factory(name="ProdNetworks") network = network_factory( address="192.168.1.0/24", first_ip="192.168.1.10", last_ip="192.168.1.250", - domain=domain, + scope=scope, ) name = "myhost" ip = "192.168.1.11" @@ -393,17 +393,17 @@ def test_create_host_invalid_fields( def test_create_interface( - client, host_factory, domain_factory, network_factory, interface_factory + client, host_factory, network_scope_factory, network_factory, interface_factory ): host = host_factory(name="myhost") - domain = domain_factory(name="prod.example.org") - network1 = network_factory(domain=domain) + scope = network_scope_factory(name="ProdNetworks") + network1 = network_factory(scope=scope) interface_factory(network=network1, host=host) network2 = network_factory( address="192.168.2.0/24", first_ip="192.168.2.10", last_ip="192.168.2.250", - domain=domain, + scope=scope, ) name = host.name + "-2" ip = "192.168.2.11" @@ -447,17 +447,17 @@ def check_vm_creation_response(response, success=True): def test_create_vm( client, - domain_factory, + network_scope_factory, network_factory, device_type_factory, host_factory, interface_factory, ): virtualmachine = device_type_factory(name="VirtualMachine") - domain_prod = domain_factory(name="prod.example.org") - domain_lab = domain_factory(name="lab.example.org") - network_prod = network_factory(domain=domain_prod) - network_lab = network_factory(domain=domain_lab) + scope_prod = network_scope_factory(name="ProdNetworks") + scope_lab = network_scope_factory(name="LabNetworks") + network_prod = network_factory(scope=scope_prod) + network_lab = network_factory(scope=scope_lab) vm_prod = host_factory(device_type=virtualmachine) interface_factory(name=vm_prod.name, host=vm_prod, network=network_prod) vioc_prod = host_factory(device_type=virtualmachine, is_ioc=True)