Skip to content

Commit

Permalink
roles: extended gpo feature to samba role
Browse files Browse the repository at this point in the history
* added SambaSite object
* added SambaComputer object
* added GenericGPO class and methods
* added some ldap variables to perform ldap functions
  • Loading branch information
Dan Lavu committed Sep 16, 2024
1 parent 0b213ff commit 506357b
Show file tree
Hide file tree
Showing 4 changed files with 524 additions and 31 deletions.
3 changes: 3 additions & 0 deletions sssd_test_framework/hosts/samba.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ def __init__(self, *args, **kwargs) -> None:

self._features: dict[str, bool] | None = None

self.admin: str = self.config.get("username", "Administrator")
"""Username of the admin user, defaults to value of ``Administrator``."""

self.adminpw: str = self.config.get("adminpw", self.bindpw)
"""Password of the admin user, defaults to value of ``bindpw``."""

Expand Down
64 changes: 38 additions & 26 deletions sssd_test_framework/roles/ad.py
Original file line number Diff line number Diff line change
Expand Up @@ -1655,16 +1655,18 @@ def __init__(self, role: AD, name: str) -> None:
self._search_base: str = f"cn=policies,cn=system,{self.role.host.naming_context}"
"""Group policy search base."""

self._dn = self.get("DistinguishedName")
self._dn = self._get("DistinguishedName")
"""Group policy dn."""

self._cn = self.get("CN")
self._cn = self._get("CN")
"""Group policy cn."""

def get(self, key: str) -> str | None:
def _get(self, key: str) -> str | None:
"""
Get group policy attributes.
This method is unique for the GPO class, unlike SambaGPO class, the ADObject class is not inherited.
:param key: Attribute to get.
:type key: str
:return: Key value.
Expand Down Expand Up @@ -1713,8 +1715,8 @@ def add(self) -> GPO:
"""
self.role.host.conn.run(f'New-GPO -name "{self.name}"')

self._cn = self.get("CN")
self._dn = self.get("DistinguishedName")
self._cn = self._get("CN")
self._dn = self._get("DistinguishedName")

self.role.host.conn.run(
rf"""
Expand All @@ -1733,43 +1735,53 @@ def add(self) -> GPO:

def link(
self,
op: str | None = "New",
target: str | None = None,
args: list[str] | str | None = None,
enforced: bool | None = None,
disabled: bool | None = False,
order: int | None = 0,
) -> GPO:
"""
Link the group policy to the a target object inside the directory, a site, domain or an ou.
..Note::
The New and Set cmdlets are identical. To modify an an existing link,
change the $op parameter to "Set", i.e. to disable 'Enforced'
Link the group policy to the target object inside the directory, a site, domain or an ou.
ou_policy.link("Set", args=["-Enforced No"])
:param op: Cmdlet operation, defaults to "New"
:type op: str, optional
:param target: Group policy target
:type target: str, optional
:param args: Additional arguments
:type args: list[str] | None, optional
:param enforced: Enforced the policy
:type enforced: bool, optional
:param disabled: Disable the policy
:type disabled: bool, optional
:param order: Order number
:type order: int, optional
:return: Group policy object
:rtype: GPO
"""
if args is None:
args = []
args: str = ""

if isinstance(args, list):
args = " ".join(args)
elif args is None:
args = ""
if enforced is True:
args = args + " -Enforce Yes"
if enforced is False:
args = args + " -Enforce No"

if disabled is True:
args = args + " -LinkEnabled No"
else:
args = args + " -LinkEnabled Yes"

if order != 0:
args = args + f" -Order {str(order)}"

if target is None and self.target is None:
self.target = "Default-First-Site-Name"

if target is not None and self.target is None:
self.target = target

self.role.host.conn.run(f'{op}-GPLink -Guid "{self._cn}" -Target "{self.target}" -LinkEnabled Yes {args}')
# The cmdlets take the same arguements, but one is for new links and the other is for existing links.
# This is combined to simplify gpo management.
new_link = self.role.host.conn.run(
f'New-GPLink -Guid "{self._cn}" -Target "{self.target}" {args}', raise_on_error=False
)
if new_link.rc != 0:
self.role.host.conn.run(f'Set-GPLink -Guid "{self._cn}" -Target "{self.target}" {args}')

return self

Expand Down Expand Up @@ -1836,7 +1848,7 @@ def policy(self, logon_rights: dict[str, list[ADObject]], cfg: dict[str, Any] |
This method does the remaining configuration of the group policy. It updates
'GptTmpl.inf' with security logon right keys with the SIDs of users and groups
objects. The *Remote* keys can be omitted, in which the corresponding keys values
objects. The *Remote* keys can be omitted, in which the interactive key's value
will then be used.
To add users and groups to the policy, the SID must be used for the values. The
Expand Down
106 changes: 106 additions & 0 deletions sssd_test_framework/roles/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"GenericAutomount",
"GenericAutomountMap",
"GenericAutomountKey",
"GenericGPO",
]


Expand Down Expand Up @@ -255,6 +256,39 @@ def test_example(client: Client, provider: GenericProvider, nfs: NFS):
"""
pass

@abstractmethod
def gpo(self, name: str) -> GenericGPO:
"""
Get group policy object.
.. code-block:: python
:caption: Example usage
@pytest.mark.topology(KnownTopologies.GenericAD)
def test_gpo_is_set_to_enforcing(client: Client, provider: GenericProvider):
user = provider.user("user").add()
allow_user = provider.user("allow_user").add()
deny_user = provider.user("deny_user").add()
provider.gpo("test policy").add().policy(
{
"SeInteractiveLogonRight": [allow_user, ad.group("Domain Admins")],
"SeRemoteInteractiveLogonRight": [allow_user, ad.group("Domain Admins")],
"SeDenyInteractiveLogonRight": [deny_user],
"SeDenyRemoteInteractiveLogonRight": [deny_user],
}
).link()
client.sssd.domain["ad_gpo_access_control"] = "enforcing"
client.sssd.start()
assert client.auth.ssh.password(username="allow_user", password="Secret123")
assert not client.auth.ssh.password(username="user", password="Secret123")
assert not client.auth.ssh.password(username="deny_user", password="Secret123")
"""
pass


class GenericADProvider(GenericProvider):
"""
Expand Down Expand Up @@ -961,3 +995,75 @@ def dump(self) -> str:
@abstractmethod
def __str__(self) -> str:
pass


class GenericGPO(
ABC,
BaseObject,
):
"""
Generic GPO management.
"""

@property
@abstractmethod
def name(self):
"""
GPO name.
"""
pass

@abstractmethod
def get(self, key: str) -> str | None:
"""
Get GPO attribute.
"""
pass

@abstractmethod
def delete(self) -> None:
"""
Delete GPO.
"""
pass

@abstractmethod
def add(self) -> GenericGPO:
"""
Add GPO.
"""
pass

@abstractmethod
def link(
self,
op: str | None = None,
target: str | None = None,
enforced: bool | None = False,
disabled: bool | None = False,
) -> GenericGPO:
"""
Link GPO.
"""
pass

@abstractmethod
def unlink(self) -> None:
"""
Unlink GPO.
"""
pass

@abstractmethod
def permissions(self, target: str, permission_level: str, target_type: str | None = "Group") -> GenericGPO:
"""
Configure GPO permissions.
"""
pass

@abstractmethod
def policy(self, logon_rights: dict[str, list[GenericUser]], cfg: dict[str, Any] | None = None) -> GenericGPO:
"""
GPO configuration.
"""
pass
Loading

0 comments on commit 506357b

Please sign in to comment.