Skip to content

Commit

Permalink
roles: added password policy utilities to ad role
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan Lavu committed Nov 29, 2024
1 parent 4ac05b2 commit a0156fe
Showing 1 changed file with 124 additions and 1 deletion.
125 changes: 124 additions & 1 deletion sssd_test_framework/roles/ad.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from pytest_mh.conn import ProcessResult

from ..hosts.ad import ADHost
from ..misc import attrs_include_value, attrs_parse, attrs_to_hash
from ..misc import attrs_include_value, attrs_parse, attrs_to_hash, seconds_to_timespan
from .base import BaseObject, BaseWindowsRole, DeleteAttribute
from .ldap import LDAPNetgroupMember
from .nfs import NFSExport
Expand Down Expand Up @@ -358,6 +358,30 @@ def test_ad__gpo_is_set_to_enforcing(client: Client, ad: AD):
"""
return GPO(self, name)

@property
def password(self) -> ADPasswordPolicy:
"""
Domain password policy management.
.. code-block:: python
:caption: Example usage
@pytest.mark.topology(KnownTopology.AD
def test_example(client: Client, ad: AD):
# Enable password complexity
ad.password.complexity(enable=True)
# Set 3 login attempts and 30 lockout duration
ad.password.lockout(attempts=3, duration=30)
# Set password length requirement to 12 characters
ad.password.requirement(length=12)
# Set password max age to 30 seconds
ad.password.age(max=30
"""
return ADPasswordPolicy(self)

def sudorule(self, name: str, basedn: ADObject | str | None = "ou=sudoers") -> ADSudoRule:
"""
Get sudo rule object.
Expand Down Expand Up @@ -911,6 +935,18 @@ def expire(self, expiration: str = "19700101000000") -> ADUser:

return self

@property
def password_change_at_logon(self) -> ADUser:
"""
Force user to change password next logon.
:return: Self.
:rtype: ADUser
"""
self.role.host.conn.run(f"Set-ADUser -Identity {self.name} -ChangePasswordAtLogon:$true")

return self

def passkey_add(self, passkey_mapping: str) -> ADUser:
"""
Add passkey mapping to the user.
Expand Down Expand Up @@ -2009,4 +2045,91 @@ def policy(self, logon_rights: dict[str, list[ADObject]], cfg: dict[str, Any] |
return self


class ADPasswordPolicy(BaseObject[ADHost, AD]):
"""
Password policy management.
"""

def __init__(self, role: AD):
"""
:param role: AD host object.
:type role: ADHost
"""
super().__init__(role)

def complexity(self, enable: bool) -> ADPasswordPolicy:
"""
Enable or disable password complexity.
:param enable: Enable or disable password complexity.
:type enable: bool
:return ADPasswordPolicy object.
:rtype: ADPasswordPolicy
"""
args: CLIBuilderArgs = {
"Identity": (self.cli.option.VALUE, self.role.domain),
"Complexity": (self.cli.option.SWITCH, enable),
}
self.role.host.conn.run(self.cli.command("Set-ADDefaultDomainPasswordPolicy", args))

return self

def lockout(self, duration: int, attempts: int) -> ADPasswordPolicy:
"""
Set lockout duration and login attempts.
:param duration: Duration of lockout in seconds.
:type duration: int
:param attempts: Number of login attempts.
:type attempts: int
:return: ADPasswordPolicy object.
:rtype: ADPasswordPolicy
"""
args: CLIBuilderArgs = {
"Identity": (self.cli.option.VALUE, self.role.domain),
"LockoutDuration": (self.cli.option.VALUE, seconds_to_timespan(duration)),
"LockoutThreshold": (self.cli.option.VALUE, str(attempts)),
}
self.role.host.conn.run(self.cli.command("Set-ADDefaultDomainPasswordPolicy", args))

return self

def age(self, minimum: int, maximum: int) -> ADPasswordPolicy:
"""
Set maximum and minimum password age.
:param minimum: Minimum password age in seconds.
:type minimum: int
:param maximum: Maximum password age in seconds.
:type maximum: int
:return: ADPasswordPolicy object.
:rtype: ADPasswordPolicy
"""
args: CLIBuilderArgs = {
"Identity": (self.cli.option.VALUE, self.role.domain),
"MinPasswordAge": (self.cli.option.VALUE, seconds_to_timespan(minimum)),
"MaxPasswordAge": (self.cli.option.VALUE, seconds_to_timespan(maximum)),
}
self.role.host.conn.run(self.cli.command("Set-ADDefaultDomainPasswordPolicy", args))

return self

def requirements(self, length: int) -> ADPasswordPolicy:
"""
Set password requirements, like length.
:param length: Required password character count.
:type length: int
:return: ADPasswordPolicy object.
:rtype: ADPasswordPolicy
"""
args: CLIBuilderArgs = {
"Identity": (self.cli.option.VALUE, self.role.domain),
"MinPasswordLength": (self.cli.option.VALUE, str(length)),
}
self.role.host.conn.run(self.cli.command("Set-ADDefaultDomainPasswordPolicy", args))

return self


ADNetgroupMember: TypeAlias = LDAPNetgroupMember[ADUser, ADNetgroup]

0 comments on commit a0156fe

Please sign in to comment.