Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

roles: adding gpo management to samba role #106

Merged
merged 1 commit into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
85 changes: 47 additions & 38 deletions sssd_test_framework/roles/ad.py
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ def _add(self, attrs: CLIBuilderArgs) -> None:

def _modify(self, attrs: CLIBuilderArgs) -> None:
"""
Modifiy Active Directory object.
Modify Active Directory object.

:param attrs: Object attributes in :class:`pytest_mh.cli.CLIBuilder` format, defaults to dict()
:type attrs: pytest_mh.cli.CLIBuilderArgs, optional
Expand Down Expand Up @@ -1652,19 +1652,21 @@ def __init__(self, role: AD, name: str) -> None:
self.target: str | None = None
"""Group policy target."""

self._search_base: str = f"cn=policies,cn=system,{self.role.host.naming_context}"
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:
"""
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 All @@ -1673,7 +1675,7 @@ def get(self, key: str) -> str | None:
result = self.role.host.conn.run(
rf"""
$query = "(&(ObjectClass=groupPolicyContainer)(DisplayName={self.name}))"
Get-ADObject -SearchBase "{self._search_base}" -Properties "*" -LDAPFilter $query
Get-ADObject -SearchBase "{self.search_base}" -Properties "*" -LDAPFilter $query
"""
).stdout_lines

Expand All @@ -1694,7 +1696,7 @@ def delete(self) -> None:
"""
Delete group policy object.
"""
self.role.host.conn.run(f'Remove-GPO -Guid "{self._cn}" -Confirm:$false')
self.role.host.conn.run(f'Remove-GPO -Guid "{self.cn}" -Confirm:$false')

def add(self) -> GPO:
"""
Expand All @@ -1713,13 +1715,13 @@ 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"""
Import-Module GroupPolicy, PSIni
$path = "C:\\Windows\\SYSVOL\\domain\\Policies\\{self._cn}\\Machine\\Microsoft\\Windows NT\\SecEdit"
$path = "C:\\Windows\\SYSVOL\\domain\\Policies\\{self.cn}\\Machine\\Microsoft\\Windows NT\\SecEdit"
$file = Join-Path $path GptTmpl.inf
$content = @{{'Unicode'=@{{'Unicode'='yes'}};'Version'=@{{'signature'='"$CHICAGO$"';'Revision'='1'}}}}
New-Item -Path "$path" -ItemType Directory
Expand All @@ -1733,43 +1735,50 @@ 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'

ou_policy.link("Set", args=["-Enforced No"])
Link the group policy to the target object inside the directory, a site, domain or an ou.

: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 = []

if isinstance(args, list):
args = " ".join(args)
elif args is None:
args = ""

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}')
args: CLIBuilderArgs = {
"Guid": (self.cli.option.VALUE, self.cn),
"Target": (self.cli.option.VALUE, self.target),
"Enforced": (self.cli.option.VALUE, "Yes" if enforced else "No"),
"LinkEnabled": (self.cli.option.VALUE, "Yes" if not disabled else "No"),
"Order": (self.cli.option.VALUE, order),
}

# The cmdlets take the same arguments, 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(
self.cli.command("New-GPLink", args),
raise_on_error=False,
)
if new_link.rc != 0:
self.role.host.conn.run(
self.cli.command("Set-GPLink", args),
raise_on_error=False,
)

return self

Expand All @@ -1780,7 +1789,7 @@ def unlink(self) -> GPO:
:return: Group policy object
:rtype: GPO
"""
self.role.host.conn.run(f'Remove-GPLink -Guid "{self._cn}" -Target "{self.target}"')
self.role.host.conn.run(f'Remove-GPLink -Guid "{self.cn}" -Target "{self.target}"')

return self

Expand All @@ -1806,7 +1815,7 @@ def permissions(self, target: str, permission_level: str, target_type: str | Non
# Setting the permission using ADSI is a workaround for automation.

$authenticated_users = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-11")
$gpo = Get-GPO -Guid "{self._cn}"
$gpo = Get-GPO -Guid "{self.cn}"
$gid = $gpo.id
$search_base = "cn=policies,cn=system," + "{self.host.naming_context}"
$filter = "(&(objectClass=groupPolicyContainer)(cn={{$gid}}))"
Expand All @@ -1822,7 +1831,7 @@ def permissions(self, target: str, permission_level: str, target_type: str | Non
)
else:
self.role.host.conn.run(
f'Set-GPPermission -Guid "{self._cn}" '
f'Set-GPPermission -Guid "{self.cn}" '
f'-TargetName "{target}" '
f'-PermissionLevel "{permission_level}" '
f'-TargetType "{target_type}" -Replace:$True -Confirm:$False'
Expand All @@ -1836,7 +1845,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 Expand Up @@ -1887,7 +1896,7 @@ def policy(self, logon_rights: dict[str, list[ADObject]], cfg: dict[str, Any] |
self.host.conn.run(
rf"""
Import-Module PSIni
$path = "C:\\Windows\\SYSVOL\\domain\\Policies\\{self._cn}\\Machine\\Microsoft\\Windows NT\\SecEdit"
$path = "C:\\Windows\\SYSVOL\\domain\\Policies\\{self.cn}\\Machine\\Microsoft\\Windows NT\\SecEdit"
$file = Join-Path $path GptTmpl.inf
$policy = @{{"Privilege Rights"={ps_logon_rights}}}
Out-IniFile -InputObject $policy -FilePath "$file"
Expand All @@ -1900,7 +1909,7 @@ def policy(self, logon_rights: dict[str, list[ADObject]], cfg: dict[str, Any] |
self.host.conn.run(
rf"""
Import-Module PSIni
$path = "C:\\Windows\\SYSVOL\\domain\\Policies\\{self._cn}\\Machine\\Microsoft\\Windows NT\\SecEdit"
$path = "C:\\Windows\\SYSVOL\\domain\\Policies\\{self.cn}\\Machine\\Microsoft\\Windows NT\\SecEdit"
$file = Join-Path $path GptTmpl.inf
$policy = {ps_cfg}
Out-IniFile -InputObject $policy -FilePath "$file"
Expand All @@ -1911,7 +1920,7 @@ def policy(self, logon_rights: dict[str, list[ADObject]], cfg: dict[str, Any] |
self.host.conn.run(
rf"""
$gpc = "[{{827D319E-6EAC-11D2-A4EA-00C04F79F83A}}{{803E14A0-B4FB-11D0-A0D0-00A0C90F574B}}]"
Set-ADObject -Identity "{self._dn}" -Replace @{{gPCMachineExtensionNames=$gpc}}
Set-ADObject -Identity "{self.dn}" -Replace @{{gPCMachineExtensionNames=$gpc}}
Exit 0
"""
)
Expand Down
Loading
Loading