mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
netcmd: auth policy: extract policy base commands into policy.py
Signed-off-by: Rob van der Linde <rob@catalyst.net.nz> Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
parent
c0e748f011
commit
96f00738ce
@ -20,654 +20,15 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import samba.getopt as options
|
||||
from samba.domain.models import (MAX_TGT_LIFETIME, MIN_TGT_LIFETIME,
|
||||
AuthenticationPolicy, AuthenticationSilo,
|
||||
Group, StrongNTLMPolicy)
|
||||
from samba.domain.models.exceptions import ModelError
|
||||
from samba.netcmd import Command, CommandError, Option, SuperCommand
|
||||
from samba.netcmd.validators import Range
|
||||
|
||||
|
||||
def check_similar_args(option, args):
|
||||
"""Helper method for checking similar mutually exclusive args.
|
||||
|
||||
Example: --user-allowed-to-authenticate-from and
|
||||
--user-allowed-to-authenticate-from-device-silo
|
||||
"""
|
||||
num = sum(arg is not None for arg in args)
|
||||
if num > 1:
|
||||
raise CommandError(f"{option} argument repeated {num} times.")
|
||||
|
||||
|
||||
class UserOptions(options.OptionGroup):
|
||||
"""User options used by policy create and policy modify commands."""
|
||||
|
||||
def __init__(self, parser):
|
||||
super().__init__(parser, "User Options")
|
||||
|
||||
self.add_option("--user-tgt-lifetime-mins",
|
||||
help="Ticket-Granting-Ticket lifetime for user accounts.",
|
||||
dest="tgt_lifetime", type=int, action="callback",
|
||||
callback=self.set_option,
|
||||
validators=[Range(min=MIN_TGT_LIFETIME, max=MAX_TGT_LIFETIME)])
|
||||
self.add_option("--user-allow-ntlm-auth",
|
||||
help="Allow NTLM network authentication despite the fact that the user "
|
||||
"is restricted to selected devices.",
|
||||
dest="allow_ntlm_auth", default=False,
|
||||
action="callback", callback=self.set_option)
|
||||
self.add_option("--user-allowed-to-authenticate-from",
|
||||
help="SDDL Rules setting which device the user is allowed to authenticate from.",
|
||||
type=str, dest="allowed_to_authenticate_from",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SDDL")
|
||||
self.add_option("--user-allowed-to-authenticate-from-device-silo",
|
||||
help="To authenticate, the user must log in from a device in SILO.",
|
||||
type=str, dest="allowed_to_authenticate_from_device_silo",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SILO")
|
||||
self.add_option("--user-allowed-to-authenticate-from-device-group",
|
||||
help="To authenticate, the user must log in from a device in GROUP.",
|
||||
type=str, dest="allowed_to_authenticate_from_device_group",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="GROUP")
|
||||
self.add_option("--user-allowed-to-authenticate-to",
|
||||
help="A target service, on a user account, requires the connecting user to match SDDL",
|
||||
type=str, dest="allowed_to_authenticate_to",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SDDL")
|
||||
self.add_option("--user-allowed-to-authenticate-to-by-group",
|
||||
help="A target service, on a user account, requires the connecting user to be in GROUP",
|
||||
type=str, dest="allowed_to_authenticate_to_by_group",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="GROUP")
|
||||
self.add_option("--user-allowed-to-authenticate-to-by-silo",
|
||||
help="A target service, on a user account, requires the connecting user to be in SILO",
|
||||
type=str, dest="allowed_to_authenticate_to_by_silo",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SILO")
|
||||
|
||||
|
||||
class ServiceOptions(options.OptionGroup):
|
||||
"""Service options used by policy create and policy modify commands."""
|
||||
|
||||
def __init__(self, parser):
|
||||
super().__init__(parser, "Service Options")
|
||||
|
||||
self.add_option("--service-tgt-lifetime-mins",
|
||||
help="Ticket-Granting-Ticket lifetime for service accounts.",
|
||||
dest="tgt_lifetime", type=int, action="callback",
|
||||
callback=self.set_option,
|
||||
validators=[Range(min=MIN_TGT_LIFETIME, max=MAX_TGT_LIFETIME)])
|
||||
self.add_option("--service-allow-ntlm-auth",
|
||||
help="Allow NTLM network authentication despite "
|
||||
"the fact that the service account "
|
||||
"is restricted to selected devices.",
|
||||
dest="allow_ntlm_auth", default=False,
|
||||
action="callback", callback=self.set_option)
|
||||
self.add_option("--service-allowed-to-authenticate-from",
|
||||
help="SDDL Rules setting which device the "
|
||||
"service account is allowed to authenticate from.",
|
||||
type=str, dest="allowed_to_authenticate_from",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SDDL")
|
||||
self.add_option("--service-allowed-to-authenticate-from-device-silo",
|
||||
help="To authenticate, the service must authenticate on a device in SILO.",
|
||||
type=str, dest="allowed_to_authenticate_from_device_silo",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SILO")
|
||||
self.add_option("--service-allowed-to-authenticate-from-device-group",
|
||||
help="To authenticate, the service must authenticate on a device in GROUP.",
|
||||
type=str, dest="allowed_to_authenticate_from_device_group",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="GROUP")
|
||||
self.add_option("--service-allowed-to-authenticate-to",
|
||||
help="The target service requires the connecting user to match SDDL",
|
||||
type=str, dest="allowed_to_authenticate_to",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SDDL")
|
||||
self.add_option("--service-allowed-to-authenticate-to-by-group",
|
||||
help="The target service requires the connecting user to be in GROUP",
|
||||
type=str, dest="allowed_to_authenticate_to_by_group",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="GROUP")
|
||||
self.add_option("--service-allowed-to-authenticate-to-by-silo",
|
||||
help="The target service requires the connecting user to be in SILO",
|
||||
type=str, dest="allowed_to_authenticate_to_by_silo",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SILO")
|
||||
|
||||
|
||||
class ComputerOptions(options.OptionGroup):
|
||||
"""Computer options used by policy create and policy modify commands."""
|
||||
|
||||
def __init__(self, parser):
|
||||
super().__init__(parser, "Computer Options")
|
||||
|
||||
self.add_option("--computer-tgt-lifetime-mins",
|
||||
help="Ticket-Granting-Ticket lifetime for computer accounts.",
|
||||
dest="tgt_lifetime", type=int, action="callback",
|
||||
callback=self.set_option,
|
||||
validators=[Range(min=MIN_TGT_LIFETIME, max=MAX_TGT_LIFETIME)])
|
||||
self.add_option("--computer-allowed-to-authenticate-to",
|
||||
help="The computer account (server, workstation) service requires the connecting user to match SDDL",
|
||||
type=str, dest="allowed_to_authenticate_to",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SDDL")
|
||||
self.add_option("--computer-allowed-to-authenticate-to-by-group",
|
||||
help="The computer account (server, workstation) service requires the connecting user to be in GROUP",
|
||||
type=str, dest="allowed_to_authenticate_to_by_group",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="GROUP")
|
||||
self.add_option("--computer-allowed-to-authenticate-to-by-silo",
|
||||
help="The computer account (server, workstation) service requires the connecting user to be in SILO",
|
||||
type=str, dest="allowed_to_authenticate_to_by_silo",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SILO")
|
||||
|
||||
|
||||
class cmd_domain_auth_policy_list(Command):
|
||||
"""List authentication policies on the domain."""
|
||||
|
||||
synopsis = "%prog -H <URL> [options]"
|
||||
|
||||
takes_optiongroups = {
|
||||
"sambaopts": options.SambaOptions,
|
||||
"credopts": options.CredentialsOptions,
|
||||
"hostopts": options.HostOptions,
|
||||
}
|
||||
|
||||
takes_options = [
|
||||
Option("--json", help="Output results in JSON format.",
|
||||
dest="output_format", action="store_const", const="json"),
|
||||
]
|
||||
|
||||
def run(self, hostopts=None, sambaopts=None, credopts=None,
|
||||
output_format=None):
|
||||
|
||||
ldb = self.ldb_connect(hostopts, sambaopts, credopts)
|
||||
|
||||
try:
|
||||
policies = AuthenticationPolicy.query(ldb)
|
||||
except ModelError as e:
|
||||
raise CommandError(e)
|
||||
|
||||
# Using json output format gives more detail.
|
||||
if output_format == "json":
|
||||
self.print_json({policy.name: policy for policy in policies})
|
||||
else:
|
||||
for policy in policies:
|
||||
print(policy.name, file=self.outf)
|
||||
|
||||
|
||||
class cmd_domain_auth_policy_view(Command):
|
||||
"""View an authentication policy on the domain."""
|
||||
|
||||
synopsis = "%prog -H <URL> [options]"
|
||||
|
||||
takes_optiongroups = {
|
||||
"sambaopts": options.SambaOptions,
|
||||
"credopts": options.CredentialsOptions,
|
||||
"hostopts": options.HostOptions,
|
||||
}
|
||||
|
||||
takes_options = [
|
||||
Option("--name",
|
||||
help="Name of authentication policy to view (required).",
|
||||
dest="name", action="store", type=str, required=True),
|
||||
]
|
||||
|
||||
def run(self, hostopts=None, sambaopts=None, credopts=None, name=None):
|
||||
|
||||
ldb = self.ldb_connect(hostopts, sambaopts, credopts)
|
||||
|
||||
try:
|
||||
policy = AuthenticationPolicy.get(ldb, cn=name)
|
||||
except ModelError as e:
|
||||
raise CommandError(e)
|
||||
|
||||
# Check if authentication policy exists first.
|
||||
if policy is None:
|
||||
raise CommandError(f"Authentication policy {name} not found.")
|
||||
|
||||
# Display policy as JSON.
|
||||
self.print_json(policy.as_dict())
|
||||
|
||||
|
||||
class cmd_domain_auth_policy_create(Command):
|
||||
"""Create an authentication policy on the domain."""
|
||||
|
||||
synopsis = "%prog -H <URL> [options]"
|
||||
|
||||
takes_optiongroups = {
|
||||
"sambaopts": options.SambaOptions,
|
||||
"credopts": options.CredentialsOptions,
|
||||
"hostopts": options.HostOptions,
|
||||
"useropts": UserOptions,
|
||||
"serviceopts": ServiceOptions,
|
||||
"computeropts": ComputerOptions,
|
||||
}
|
||||
|
||||
takes_options = [
|
||||
Option("--name", help="Name of authentication policy (required).",
|
||||
dest="name", action="store", type=str, required=True),
|
||||
Option("--description",
|
||||
help="Optional description for authentication policy.",
|
||||
dest="description", action="store", type=str),
|
||||
Option("--protect",
|
||||
help="Protect authentication silo from accidental deletion.",
|
||||
dest="protect", action="store_true"),
|
||||
Option("--unprotect",
|
||||
help="Unprotect authentication silo from accidental deletion.",
|
||||
dest="unprotect", action="store_true"),
|
||||
Option("--audit",
|
||||
help="Only audit authentication policy.",
|
||||
dest="audit", action="store_true"),
|
||||
Option("--enforce",
|
||||
help="Enforce authentication policy.",
|
||||
dest="enforce", action="store_true"),
|
||||
Option("--strong-ntlm-policy",
|
||||
help=f"Strong NTLM Policy ({StrongNTLMPolicy.choices_str()}).",
|
||||
dest="strong_ntlm_policy", type="choice", action="store",
|
||||
choices=StrongNTLMPolicy.get_choices(),
|
||||
default="Disabled"),
|
||||
]
|
||||
|
||||
def run(self, hostopts=None, sambaopts=None, credopts=None, useropts=None,
|
||||
serviceopts=None, computeropts=None, name=None, description=None,
|
||||
protect=None, unprotect=None, audit=None, enforce=None,
|
||||
strong_ntlm_policy=None):
|
||||
|
||||
if protect and unprotect:
|
||||
raise CommandError("--protect and --unprotect cannot be used together.")
|
||||
if audit and enforce:
|
||||
raise CommandError("--audit and --enforce cannot be used together.")
|
||||
|
||||
# Check for repeated, similar arguments.
|
||||
check_similar_args("--user-allowed-to-authenticate-from",
|
||||
[useropts.allowed_to_authenticate_from,
|
||||
useropts.allowed_to_authenticate_from_device_group,
|
||||
useropts.allowed_to_authenticate_from_device_silo])
|
||||
check_similar_args("--user-allowed-to-authenticate-to",
|
||||
[useropts.allowed_to_authenticate_to,
|
||||
useropts.allowed_to_authenticate_to_by_group,
|
||||
useropts.allowed_to_authenticate_to_by_silo])
|
||||
check_similar_args("--service-allowed-to-authenticate-from",
|
||||
[serviceopts.allowed_to_authenticate_from,
|
||||
serviceopts.allowed_to_authenticate_from_device_group,
|
||||
serviceopts.allowed_to_authenticate_from_device_silo])
|
||||
check_similar_args("--service-allowed-to-authenticate-to",
|
||||
[serviceopts.allowed_to_authenticate_to,
|
||||
serviceopts.allowed_to_authenticate_to_by_group,
|
||||
serviceopts.allowed_to_authenticate_to_by_silo])
|
||||
check_similar_args("--computer-allowed-to-authenticate-to",
|
||||
[computeropts.allowed_to_authenticate_to,
|
||||
computeropts.allowed_to_authenticate_to_by_group,
|
||||
computeropts.allowed_to_authenticate_to_by_silo])
|
||||
|
||||
ldb = self.ldb_connect(hostopts, sambaopts, credopts)
|
||||
|
||||
# Generate SDDL for authenticating users from a device in a group
|
||||
if useropts.allowed_to_authenticate_from_device_group:
|
||||
group = Group.get(
|
||||
ldb, cn=useropts.allowed_to_authenticate_from_device_group)
|
||||
useropts.allowed_to_authenticate_from = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating users from a device in a silo
|
||||
if useropts.allowed_to_authenticate_from_device_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=useropts.allowed_to_authenticate_from_device_silo)
|
||||
useropts.allowed_to_authenticate_from = silo.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating user accounts to a group
|
||||
if useropts.allowed_to_authenticate_to_by_group:
|
||||
group = Group.get(
|
||||
ldb, cn=useropts.allowed_to_authenticate_to_by_group)
|
||||
useropts.allowed_to_authenticate_to = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating user accounts to a silo
|
||||
if useropts.allowed_to_authenticate_to_by_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=useropts.allowed_to_authenticate_to_by_silo)
|
||||
useropts.allowed_to_authenticate_to = silo.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating service accounts from a device in a group
|
||||
if serviceopts.allowed_to_authenticate_from_device_group:
|
||||
group = Group.get(
|
||||
ldb, cn=serviceopts.allowed_to_authenticate_from_device_group)
|
||||
serviceopts.allowed_to_authenticate_from = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating service accounts from a device in a silo
|
||||
if serviceopts.allowed_to_authenticate_from_device_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=serviceopts.allowed_to_authenticate_from_device_silo)
|
||||
serviceopts.allowed_to_authenticate_from = silo.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating service accounts to a group
|
||||
if serviceopts.allowed_to_authenticate_to_by_group:
|
||||
group = Group.get(
|
||||
ldb, cn=serviceopts.allowed_to_authenticate_to_by_group)
|
||||
serviceopts.allowed_to_authenticate_to = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating service accounts to a silo
|
||||
if serviceopts.allowed_to_authenticate_to_by_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=serviceopts.allowed_to_authenticate_to_by_silo)
|
||||
serviceopts.allowed_to_authenticate_to = silo.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating computer accounts to a group
|
||||
if computeropts.allowed_to_authenticate_to_by_group:
|
||||
group = Group.get(
|
||||
ldb, cn=computeropts.allowed_to_authenticate_to_by_group)
|
||||
computeropts.allowed_to_authenticate_to = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating computer accounts to a silo
|
||||
if computeropts.allowed_to_authenticate_to_by_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=computeropts.allowed_to_authenticate_to_by_silo)
|
||||
computeropts.allowed_to_authenticate_to = silo.get_authentication_sddl()
|
||||
|
||||
try:
|
||||
policy = AuthenticationPolicy.get(ldb, cn=name)
|
||||
except ModelError as e:
|
||||
raise CommandError(e)
|
||||
|
||||
# Make sure authentication policy doesn't already exist.
|
||||
if policy is not None:
|
||||
raise CommandError(f"Authentication policy {name} already exists.")
|
||||
|
||||
# New policy object.
|
||||
policy = AuthenticationPolicy(
|
||||
cn=name,
|
||||
description=description,
|
||||
strong_ntlm_policy=StrongNTLMPolicy[strong_ntlm_policy.upper()],
|
||||
user_allow_ntlm_auth=useropts.allow_ntlm_auth,
|
||||
user_tgt_lifetime=useropts.tgt_lifetime,
|
||||
user_allowed_to_authenticate_from=useropts.allowed_to_authenticate_from,
|
||||
user_allowed_to_authenticate_to=useropts.allowed_to_authenticate_to,
|
||||
service_allow_ntlm_auth=serviceopts.allow_ntlm_auth,
|
||||
service_tgt_lifetime=serviceopts.tgt_lifetime,
|
||||
service_allowed_to_authenticate_from=serviceopts.allowed_to_authenticate_from,
|
||||
service_allowed_to_authenticate_to=serviceopts.allowed_to_authenticate_to,
|
||||
computer_tgt_lifetime=computeropts.tgt_lifetime,
|
||||
computer_allowed_to_authenticate_to=computeropts.allowed_to_authenticate_to,
|
||||
)
|
||||
|
||||
# Either --enforce will be set or --audit but never both.
|
||||
# The default if both are missing is enforce=True.
|
||||
if enforce is not None:
|
||||
policy.enforced = enforce
|
||||
else:
|
||||
policy.enforced = not audit
|
||||
|
||||
# Create policy.
|
||||
try:
|
||||
policy.save(ldb)
|
||||
|
||||
if protect:
|
||||
policy.protect(ldb)
|
||||
except ModelError as e:
|
||||
raise CommandError(e)
|
||||
|
||||
# Authentication policy created successfully.
|
||||
print(f"Created authentication policy: {name}", file=self.outf)
|
||||
|
||||
|
||||
class cmd_domain_auth_policy_modify(Command):
|
||||
"""Modify authentication policies on the domain."""
|
||||
|
||||
synopsis = "%prog -H <URL> [options]"
|
||||
|
||||
takes_optiongroups = {
|
||||
"sambaopts": options.SambaOptions,
|
||||
"credopts": options.CredentialsOptions,
|
||||
"hostopts": options.HostOptions,
|
||||
"useropts": UserOptions,
|
||||
"serviceopts": ServiceOptions,
|
||||
"computeropts": ComputerOptions,
|
||||
}
|
||||
|
||||
takes_options = [
|
||||
Option("--name", help="Name of authentication policy (required).",
|
||||
dest="name", action="store", type=str, required=True),
|
||||
Option("--description",
|
||||
help="Optional description for authentication policy.",
|
||||
dest="description", action="store", type=str),
|
||||
Option("--protect",
|
||||
help="Protect authentication silo from accidental deletion.",
|
||||
dest="protect", action="store_true"),
|
||||
Option("--unprotect",
|
||||
help="Unprotect authentication silo from accidental deletion.",
|
||||
dest="unprotect", action="store_true"),
|
||||
Option("--audit",
|
||||
help="Only audit authentication policy.",
|
||||
dest="audit", action="store_true"),
|
||||
Option("--enforce",
|
||||
help="Enforce authentication policy.",
|
||||
dest="enforce", action="store_true"),
|
||||
Option("--strong-ntlm-policy",
|
||||
help=f"Strong NTLM Policy ({StrongNTLMPolicy.choices_str()}).",
|
||||
dest="strong_ntlm_policy", type="choice", action="store",
|
||||
choices=StrongNTLMPolicy.get_choices()),
|
||||
]
|
||||
|
||||
def run(self, hostopts=None, sambaopts=None, credopts=None, useropts=None,
|
||||
serviceopts=None, computeropts=None, name=None, description=None,
|
||||
protect=None, unprotect=None, audit=None, enforce=None,
|
||||
strong_ntlm_policy=None):
|
||||
|
||||
if protect and unprotect:
|
||||
raise CommandError("--protect and --unprotect cannot be used together.")
|
||||
if audit and enforce:
|
||||
raise CommandError("--audit and --enforce cannot be used together.")
|
||||
|
||||
# Check for repeated, similar arguments.
|
||||
check_similar_args("--user-allowed-to-authenticate-from",
|
||||
[useropts.allowed_to_authenticate_from,
|
||||
useropts.allowed_to_authenticate_from_device_group,
|
||||
useropts.allowed_to_authenticate_from_device_silo])
|
||||
check_similar_args("--user-allowed-to-authenticate-to",
|
||||
[useropts.allowed_to_authenticate_to,
|
||||
useropts.allowed_to_authenticate_to_by_group,
|
||||
useropts.allowed_to_authenticate_to_by_silo])
|
||||
check_similar_args("--service-allowed-to-authenticate-from",
|
||||
[serviceopts.allowed_to_authenticate_from,
|
||||
serviceopts.allowed_to_authenticate_from_device_group,
|
||||
serviceopts.allowed_to_authenticate_from_device_silo])
|
||||
check_similar_args("--service-allowed-to-authenticate-to",
|
||||
[serviceopts.allowed_to_authenticate_to,
|
||||
serviceopts.allowed_to_authenticate_to_by_group,
|
||||
serviceopts.allowed_to_authenticate_to_by_silo])
|
||||
check_similar_args("--computer-allowed-to-authenticate-to",
|
||||
[computeropts.allowed_to_authenticate_to,
|
||||
computeropts.allowed_to_authenticate_to_by_group,
|
||||
computeropts.allowed_to_authenticate_to_by_silo])
|
||||
|
||||
ldb = self.ldb_connect(hostopts, sambaopts, credopts)
|
||||
|
||||
# Generate SDDL for authenticating users from a device in a group
|
||||
if useropts.allowed_to_authenticate_from_device_group:
|
||||
group = Group.get(
|
||||
ldb, cn=useropts.allowed_to_authenticate_from_device_group)
|
||||
useropts.allowed_to_authenticate_from = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating users from a device in a silo
|
||||
if useropts.allowed_to_authenticate_from_device_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=useropts.allowed_to_authenticate_from_device_silo)
|
||||
useropts.allowed_to_authenticate_from = silo.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating user accounts to a group
|
||||
if useropts.allowed_to_authenticate_to_by_group:
|
||||
group = Group.get(
|
||||
ldb, cn=useropts.allowed_to_authenticate_to_by_group)
|
||||
useropts.allowed_to_authenticate_to = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating user accounts to a silo
|
||||
if useropts.allowed_to_authenticate_to_by_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=useropts.allowed_to_authenticate_to_by_silo)
|
||||
useropts.allowed_to_authenticate_to = silo.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating users from a device a device in a group
|
||||
if serviceopts.allowed_to_authenticate_from_device_group:
|
||||
group = Group.get(
|
||||
ldb, cn=serviceopts.allowed_to_authenticate_from_device_group)
|
||||
serviceopts.allowed_to_authenticate_from = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating service accounts from a device in a silo
|
||||
if serviceopts.allowed_to_authenticate_from_device_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=serviceopts.allowed_to_authenticate_from_device_silo)
|
||||
serviceopts.allowed_to_authenticate_from = silo.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating service accounts to a group
|
||||
if serviceopts.allowed_to_authenticate_to_by_group:
|
||||
group = Group.get(
|
||||
ldb, cn=serviceopts.allowed_to_authenticate_to_by_group)
|
||||
serviceopts.allowed_to_authenticate_to = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating service accounts to a silo
|
||||
if serviceopts.allowed_to_authenticate_to_by_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=serviceopts.allowed_to_authenticate_to_by_silo)
|
||||
serviceopts.allowed_to_authenticate_to = silo.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating computer accounts to a group
|
||||
if computeropts.allowed_to_authenticate_to_by_group:
|
||||
group = Group.get(
|
||||
ldb, cn=computeropts.allowed_to_authenticate_to_by_group)
|
||||
computeropts.allowed_to_authenticate_to = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating computer accounts to a silo
|
||||
if computeropts.allowed_to_authenticate_to_by_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=computeropts.allowed_to_authenticate_to_by_silo)
|
||||
computeropts.allowed_to_authenticate_to = silo.get_authentication_sddl()
|
||||
|
||||
try:
|
||||
policy = AuthenticationPolicy.get(ldb, cn=name)
|
||||
except ModelError as e:
|
||||
raise CommandError(e)
|
||||
|
||||
# Check if authentication policy exists.
|
||||
if policy is None:
|
||||
raise CommandError(f"Authentication policy {name} not found.")
|
||||
|
||||
# Either --enforce will be set or --audit but never both.
|
||||
if enforce:
|
||||
policy.enforced = True
|
||||
elif audit:
|
||||
policy.enforced = False
|
||||
|
||||
# Update the description.
|
||||
if description is not None:
|
||||
policy.description = description
|
||||
|
||||
# User sign on
|
||||
###############
|
||||
|
||||
if strong_ntlm_policy is not None:
|
||||
policy.strong_ntlm_policy = \
|
||||
StrongNTLMPolicy[strong_ntlm_policy.upper()]
|
||||
|
||||
if useropts.tgt_lifetime is not None:
|
||||
policy.user_tgt_lifetime = useropts.tgt_lifetime
|
||||
|
||||
if useropts.allowed_to_authenticate_from is not None:
|
||||
policy.user_allowed_to_authenticate_from = \
|
||||
useropts.allowed_to_authenticate_from
|
||||
|
||||
if useropts.allowed_to_authenticate_to is not None:
|
||||
policy.user_allowed_to_authenticate_to = \
|
||||
useropts.allowed_to_authenticate_to
|
||||
|
||||
# Service sign on
|
||||
##################
|
||||
|
||||
if serviceopts.tgt_lifetime is not None:
|
||||
policy.service_tgt_lifetime = serviceopts.tgt_lifetime
|
||||
|
||||
if serviceopts.allowed_to_authenticate_from is not None:
|
||||
policy.service_allowed_to_authenticate_from = \
|
||||
serviceopts.allowed_to_authenticate_from
|
||||
|
||||
if serviceopts.allowed_to_authenticate_to is not None:
|
||||
policy.service_allowed_to_authenticate_to = \
|
||||
serviceopts.allowed_to_authenticate_to
|
||||
|
||||
# Computer
|
||||
###########
|
||||
|
||||
if computeropts.tgt_lifetime is not None:
|
||||
policy.computer_tgt_lifetime = computeropts.tgt_lifetime
|
||||
|
||||
if computeropts.allowed_to_authenticate_to is not None:
|
||||
policy.computer_allowed_to_authenticate_to = \
|
||||
computeropts.allowed_to_authenticate_to
|
||||
|
||||
# Update policy.
|
||||
try:
|
||||
policy.save(ldb)
|
||||
|
||||
if protect:
|
||||
policy.protect(ldb)
|
||||
elif unprotect:
|
||||
policy.unprotect(ldb)
|
||||
except ModelError as e:
|
||||
raise CommandError(e)
|
||||
|
||||
# Authentication policy updated successfully.
|
||||
print(f"Updated authentication policy: {name}", file=self.outf)
|
||||
|
||||
|
||||
class cmd_domain_auth_policy_delete(Command):
|
||||
"""Delete authentication policies on the domain."""
|
||||
|
||||
synopsis = "%prog -H <URL> [options]"
|
||||
|
||||
takes_optiongroups = {
|
||||
"sambaopts": options.SambaOptions,
|
||||
"credopts": options.CredentialsOptions,
|
||||
"hostopts": options.HostOptions,
|
||||
}
|
||||
|
||||
takes_options = [
|
||||
Option("--name", help="Name of authentication policy (required).",
|
||||
dest="name", action="store", type=str, required=True),
|
||||
Option("--force", help="Force delete protected authentication policy.",
|
||||
dest="force", action="store_true")
|
||||
]
|
||||
|
||||
def run(self, hostopts=None, sambaopts=None, credopts=None, name=None,
|
||||
force=None):
|
||||
|
||||
ldb = self.ldb_connect(hostopts, sambaopts, credopts)
|
||||
|
||||
try:
|
||||
policy = AuthenticationPolicy.get(ldb, cn=name)
|
||||
except ModelError as e:
|
||||
raise CommandError(e)
|
||||
|
||||
# Check if authentication policy exists first.
|
||||
if policy is None:
|
||||
raise CommandError(f"Authentication policy {name} not found.")
|
||||
|
||||
# Delete item, --force removes delete protection first.
|
||||
try:
|
||||
if force:
|
||||
policy.unprotect(ldb)
|
||||
|
||||
policy.delete(ldb)
|
||||
except ModelError as e:
|
||||
if not force:
|
||||
raise CommandError(
|
||||
f"{e}\nTry --force to delete protected authentication policies.")
|
||||
else:
|
||||
raise CommandError(e)
|
||||
|
||||
# Authentication policy deleted successfully.
|
||||
print(f"Deleted authentication policy: {name}", file=self.outf)
|
||||
from samba.netcmd import SuperCommand
|
||||
|
||||
from .policy import (
|
||||
cmd_domain_auth_policy_create,
|
||||
cmd_domain_auth_policy_delete,
|
||||
cmd_domain_auth_policy_list,
|
||||
cmd_domain_auth_policy_modify,
|
||||
cmd_domain_auth_policy_view,
|
||||
)
|
||||
|
||||
|
||||
class cmd_domain_auth_policy(SuperCommand):
|
||||
|
670
python/samba/netcmd/domain/auth/policy/policy.py
Normal file
670
python/samba/netcmd/domain/auth/policy/policy.py
Normal file
@ -0,0 +1,670 @@
|
||||
# Unix SMB/CIFS implementation.
|
||||
#
|
||||
# authentication silos - authentication policy management
|
||||
#
|
||||
# Copyright (C) Catalyst.Net Ltd. 2023
|
||||
#
|
||||
# Written by Rob van der Linde <rob@catalyst.net.nz>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import samba.getopt as options
|
||||
from samba.domain.models import (MAX_TGT_LIFETIME, MIN_TGT_LIFETIME,
|
||||
AuthenticationPolicy, AuthenticationSilo,
|
||||
Group, StrongNTLMPolicy)
|
||||
from samba.domain.models.exceptions import ModelError
|
||||
from samba.netcmd import Command, CommandError, Option
|
||||
from samba.netcmd.validators import Range
|
||||
|
||||
|
||||
def check_similar_args(option, args):
|
||||
"""Helper method for checking similar mutually exclusive args.
|
||||
|
||||
Example: --user-allowed-to-authenticate-from and
|
||||
--user-allowed-to-authenticate-from-device-silo
|
||||
"""
|
||||
num = sum(arg is not None for arg in args)
|
||||
if num > 1:
|
||||
raise CommandError(f"{option} argument repeated {num} times.")
|
||||
|
||||
|
||||
class UserOptions(options.OptionGroup):
|
||||
"""User options used by policy create and policy modify commands."""
|
||||
|
||||
def __init__(self, parser):
|
||||
super().__init__(parser, "User Options")
|
||||
|
||||
self.add_option("--user-tgt-lifetime-mins",
|
||||
help="Ticket-Granting-Ticket lifetime for user accounts.",
|
||||
dest="tgt_lifetime", type=int, action="callback",
|
||||
callback=self.set_option,
|
||||
validators=[Range(min=MIN_TGT_LIFETIME, max=MAX_TGT_LIFETIME)])
|
||||
self.add_option("--user-allow-ntlm-auth",
|
||||
help="Allow NTLM network authentication despite the fact that the user "
|
||||
"is restricted to selected devices.",
|
||||
dest="allow_ntlm_auth", default=False,
|
||||
action="callback", callback=self.set_option)
|
||||
self.add_option("--user-allowed-to-authenticate-from",
|
||||
help="SDDL Rules setting which device the user is allowed to authenticate from.",
|
||||
type=str, dest="allowed_to_authenticate_from",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SDDL")
|
||||
self.add_option("--user-allowed-to-authenticate-from-device-silo",
|
||||
help="To authenticate, the user must log in from a device in SILO.",
|
||||
type=str, dest="allowed_to_authenticate_from_device_silo",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SILO")
|
||||
self.add_option("--user-allowed-to-authenticate-from-device-group",
|
||||
help="To authenticate, the user must log in from a device in GROUP.",
|
||||
type=str, dest="allowed_to_authenticate_from_device_group",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="GROUP")
|
||||
self.add_option("--user-allowed-to-authenticate-to",
|
||||
help="A target service, on a user account, requires the connecting user to match SDDL",
|
||||
type=str, dest="allowed_to_authenticate_to",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SDDL")
|
||||
self.add_option("--user-allowed-to-authenticate-to-by-group",
|
||||
help="A target service, on a user account, requires the connecting user to be in GROUP",
|
||||
type=str, dest="allowed_to_authenticate_to_by_group",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="GROUP")
|
||||
self.add_option("--user-allowed-to-authenticate-to-by-silo",
|
||||
help="A target service, on a user account, requires the connecting user to be in SILO",
|
||||
type=str, dest="allowed_to_authenticate_to_by_silo",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SILO")
|
||||
|
||||
|
||||
class ServiceOptions(options.OptionGroup):
|
||||
"""Service options used by policy create and policy modify commands."""
|
||||
|
||||
def __init__(self, parser):
|
||||
super().__init__(parser, "Service Options")
|
||||
|
||||
self.add_option("--service-tgt-lifetime-mins",
|
||||
help="Ticket-Granting-Ticket lifetime for service accounts.",
|
||||
dest="tgt_lifetime", type=int, action="callback",
|
||||
callback=self.set_option,
|
||||
validators=[Range(min=MIN_TGT_LIFETIME, max=MAX_TGT_LIFETIME)])
|
||||
self.add_option("--service-allow-ntlm-auth",
|
||||
help="Allow NTLM network authentication despite "
|
||||
"the fact that the service account "
|
||||
"is restricted to selected devices.",
|
||||
dest="allow_ntlm_auth", default=False,
|
||||
action="callback", callback=self.set_option)
|
||||
self.add_option("--service-allowed-to-authenticate-from",
|
||||
help="SDDL Rules setting which device the "
|
||||
"service account is allowed to authenticate from.",
|
||||
type=str, dest="allowed_to_authenticate_from",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SDDL")
|
||||
self.add_option("--service-allowed-to-authenticate-from-device-silo",
|
||||
help="To authenticate, the service must authenticate on a device in SILO.",
|
||||
type=str, dest="allowed_to_authenticate_from_device_silo",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SILO")
|
||||
self.add_option("--service-allowed-to-authenticate-from-device-group",
|
||||
help="To authenticate, the service must authenticate on a device in GROUP.",
|
||||
type=str, dest="allowed_to_authenticate_from_device_group",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="GROUP")
|
||||
self.add_option("--service-allowed-to-authenticate-to",
|
||||
help="The target service requires the connecting user to match SDDL",
|
||||
type=str, dest="allowed_to_authenticate_to",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SDDL")
|
||||
self.add_option("--service-allowed-to-authenticate-to-by-group",
|
||||
help="The target service requires the connecting user to be in GROUP",
|
||||
type=str, dest="allowed_to_authenticate_to_by_group",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="GROUP")
|
||||
self.add_option("--service-allowed-to-authenticate-to-by-silo",
|
||||
help="The target service requires the connecting user to be in SILO",
|
||||
type=str, dest="allowed_to_authenticate_to_by_silo",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SILO")
|
||||
|
||||
|
||||
class ComputerOptions(options.OptionGroup):
|
||||
"""Computer options used by policy create and policy modify commands."""
|
||||
|
||||
def __init__(self, parser):
|
||||
super().__init__(parser, "Computer Options")
|
||||
|
||||
self.add_option("--computer-tgt-lifetime-mins",
|
||||
help="Ticket-Granting-Ticket lifetime for computer accounts.",
|
||||
dest="tgt_lifetime", type=int, action="callback",
|
||||
callback=self.set_option,
|
||||
validators=[Range(min=MIN_TGT_LIFETIME, max=MAX_TGT_LIFETIME)])
|
||||
self.add_option("--computer-allowed-to-authenticate-to",
|
||||
help="The computer account (server, workstation) service requires the connecting user to match SDDL",
|
||||
type=str, dest="allowed_to_authenticate_to",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SDDL")
|
||||
self.add_option("--computer-allowed-to-authenticate-to-by-group",
|
||||
help="The computer account (server, workstation) service requires the connecting user to be in GROUP",
|
||||
type=str, dest="allowed_to_authenticate_to_by_group",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="GROUP")
|
||||
self.add_option("--computer-allowed-to-authenticate-to-by-silo",
|
||||
help="The computer account (server, workstation) service requires the connecting user to be in SILO",
|
||||
type=str, dest="allowed_to_authenticate_to_by_silo",
|
||||
action="callback", callback=self.set_option,
|
||||
metavar="SILO")
|
||||
|
||||
|
||||
class cmd_domain_auth_policy_list(Command):
|
||||
"""List authentication policies on the domain."""
|
||||
|
||||
synopsis = "%prog -H <URL> [options]"
|
||||
|
||||
takes_optiongroups = {
|
||||
"sambaopts": options.SambaOptions,
|
||||
"credopts": options.CredentialsOptions,
|
||||
"hostopts": options.HostOptions,
|
||||
}
|
||||
|
||||
takes_options = [
|
||||
Option("--json", help="Output results in JSON format.",
|
||||
dest="output_format", action="store_const", const="json"),
|
||||
]
|
||||
|
||||
def run(self, hostopts=None, sambaopts=None, credopts=None,
|
||||
output_format=None):
|
||||
|
||||
ldb = self.ldb_connect(hostopts, sambaopts, credopts)
|
||||
|
||||
try:
|
||||
policies = AuthenticationPolicy.query(ldb)
|
||||
except ModelError as e:
|
||||
raise CommandError(e)
|
||||
|
||||
# Using json output format gives more detail.
|
||||
if output_format == "json":
|
||||
self.print_json({policy.name: policy for policy in policies})
|
||||
else:
|
||||
for policy in policies:
|
||||
print(policy.name, file=self.outf)
|
||||
|
||||
|
||||
class cmd_domain_auth_policy_view(Command):
|
||||
"""View an authentication policy on the domain."""
|
||||
|
||||
synopsis = "%prog -H <URL> [options]"
|
||||
|
||||
takes_optiongroups = {
|
||||
"sambaopts": options.SambaOptions,
|
||||
"credopts": options.CredentialsOptions,
|
||||
"hostopts": options.HostOptions,
|
||||
}
|
||||
|
||||
takes_options = [
|
||||
Option("--name",
|
||||
help="Name of authentication policy to view (required).",
|
||||
dest="name", action="store", type=str, required=True),
|
||||
]
|
||||
|
||||
def run(self, hostopts=None, sambaopts=None, credopts=None, name=None):
|
||||
|
||||
ldb = self.ldb_connect(hostopts, sambaopts, credopts)
|
||||
|
||||
try:
|
||||
policy = AuthenticationPolicy.get(ldb, cn=name)
|
||||
except ModelError as e:
|
||||
raise CommandError(e)
|
||||
|
||||
# Check if authentication policy exists first.
|
||||
if policy is None:
|
||||
raise CommandError(f"Authentication policy {name} not found.")
|
||||
|
||||
# Display policy as JSON.
|
||||
self.print_json(policy.as_dict())
|
||||
|
||||
|
||||
class cmd_domain_auth_policy_create(Command):
|
||||
"""Create an authentication policy on the domain."""
|
||||
|
||||
synopsis = "%prog -H <URL> [options]"
|
||||
|
||||
takes_optiongroups = {
|
||||
"sambaopts": options.SambaOptions,
|
||||
"credopts": options.CredentialsOptions,
|
||||
"hostopts": options.HostOptions,
|
||||
"useropts": UserOptions,
|
||||
"serviceopts": ServiceOptions,
|
||||
"computeropts": ComputerOptions,
|
||||
}
|
||||
|
||||
takes_options = [
|
||||
Option("--name", help="Name of authentication policy (required).",
|
||||
dest="name", action="store", type=str, required=True),
|
||||
Option("--description",
|
||||
help="Optional description for authentication policy.",
|
||||
dest="description", action="store", type=str),
|
||||
Option("--protect",
|
||||
help="Protect authentication silo from accidental deletion.",
|
||||
dest="protect", action="store_true"),
|
||||
Option("--unprotect",
|
||||
help="Unprotect authentication silo from accidental deletion.",
|
||||
dest="unprotect", action="store_true"),
|
||||
Option("--audit",
|
||||
help="Only audit authentication policy.",
|
||||
dest="audit", action="store_true"),
|
||||
Option("--enforce",
|
||||
help="Enforce authentication policy.",
|
||||
dest="enforce", action="store_true"),
|
||||
Option("--strong-ntlm-policy",
|
||||
help=f"Strong NTLM Policy ({StrongNTLMPolicy.choices_str()}).",
|
||||
dest="strong_ntlm_policy", type="choice", action="store",
|
||||
choices=StrongNTLMPolicy.get_choices(),
|
||||
default="Disabled"),
|
||||
]
|
||||
|
||||
def run(self, hostopts=None, sambaopts=None, credopts=None, useropts=None,
|
||||
serviceopts=None, computeropts=None, name=None, description=None,
|
||||
protect=None, unprotect=None, audit=None, enforce=None,
|
||||
strong_ntlm_policy=None):
|
||||
|
||||
if protect and unprotect:
|
||||
raise CommandError("--protect and --unprotect cannot be used together.")
|
||||
if audit and enforce:
|
||||
raise CommandError("--audit and --enforce cannot be used together.")
|
||||
|
||||
# Check for repeated, similar arguments.
|
||||
check_similar_args("--user-allowed-to-authenticate-from",
|
||||
[useropts.allowed_to_authenticate_from,
|
||||
useropts.allowed_to_authenticate_from_device_group,
|
||||
useropts.allowed_to_authenticate_from_device_silo])
|
||||
check_similar_args("--user-allowed-to-authenticate-to",
|
||||
[useropts.allowed_to_authenticate_to,
|
||||
useropts.allowed_to_authenticate_to_by_group,
|
||||
useropts.allowed_to_authenticate_to_by_silo])
|
||||
check_similar_args("--service-allowed-to-authenticate-from",
|
||||
[serviceopts.allowed_to_authenticate_from,
|
||||
serviceopts.allowed_to_authenticate_from_device_group,
|
||||
serviceopts.allowed_to_authenticate_from_device_silo])
|
||||
check_similar_args("--service-allowed-to-authenticate-to",
|
||||
[serviceopts.allowed_to_authenticate_to,
|
||||
serviceopts.allowed_to_authenticate_to_by_group,
|
||||
serviceopts.allowed_to_authenticate_to_by_silo])
|
||||
check_similar_args("--computer-allowed-to-authenticate-to",
|
||||
[computeropts.allowed_to_authenticate_to,
|
||||
computeropts.allowed_to_authenticate_to_by_group,
|
||||
computeropts.allowed_to_authenticate_to_by_silo])
|
||||
|
||||
ldb = self.ldb_connect(hostopts, sambaopts, credopts)
|
||||
|
||||
# Generate SDDL for authenticating users from a device in a group
|
||||
if useropts.allowed_to_authenticate_from_device_group:
|
||||
group = Group.get(
|
||||
ldb, cn=useropts.allowed_to_authenticate_from_device_group)
|
||||
useropts.allowed_to_authenticate_from = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating users from a device in a silo
|
||||
if useropts.allowed_to_authenticate_from_device_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=useropts.allowed_to_authenticate_from_device_silo)
|
||||
useropts.allowed_to_authenticate_from = silo.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating user accounts to a group
|
||||
if useropts.allowed_to_authenticate_to_by_group:
|
||||
group = Group.get(
|
||||
ldb, cn=useropts.allowed_to_authenticate_to_by_group)
|
||||
useropts.allowed_to_authenticate_to = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating user accounts to a silo
|
||||
if useropts.allowed_to_authenticate_to_by_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=useropts.allowed_to_authenticate_to_by_silo)
|
||||
useropts.allowed_to_authenticate_to = silo.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating service accounts from a device in a group
|
||||
if serviceopts.allowed_to_authenticate_from_device_group:
|
||||
group = Group.get(
|
||||
ldb, cn=serviceopts.allowed_to_authenticate_from_device_group)
|
||||
serviceopts.allowed_to_authenticate_from = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating service accounts from a device in a silo
|
||||
if serviceopts.allowed_to_authenticate_from_device_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=serviceopts.allowed_to_authenticate_from_device_silo)
|
||||
serviceopts.allowed_to_authenticate_from = silo.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating service accounts to a group
|
||||
if serviceopts.allowed_to_authenticate_to_by_group:
|
||||
group = Group.get(
|
||||
ldb, cn=serviceopts.allowed_to_authenticate_to_by_group)
|
||||
serviceopts.allowed_to_authenticate_to = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating service accounts to a silo
|
||||
if serviceopts.allowed_to_authenticate_to_by_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=serviceopts.allowed_to_authenticate_to_by_silo)
|
||||
serviceopts.allowed_to_authenticate_to = silo.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating computer accounts to a group
|
||||
if computeropts.allowed_to_authenticate_to_by_group:
|
||||
group = Group.get(
|
||||
ldb, cn=computeropts.allowed_to_authenticate_to_by_group)
|
||||
computeropts.allowed_to_authenticate_to = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating computer accounts to a silo
|
||||
if computeropts.allowed_to_authenticate_to_by_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=computeropts.allowed_to_authenticate_to_by_silo)
|
||||
computeropts.allowed_to_authenticate_to = silo.get_authentication_sddl()
|
||||
|
||||
try:
|
||||
policy = AuthenticationPolicy.get(ldb, cn=name)
|
||||
except ModelError as e:
|
||||
raise CommandError(e)
|
||||
|
||||
# Make sure authentication policy doesn't already exist.
|
||||
if policy is not None:
|
||||
raise CommandError(f"Authentication policy {name} already exists.")
|
||||
|
||||
# New policy object.
|
||||
policy = AuthenticationPolicy(
|
||||
cn=name,
|
||||
description=description,
|
||||
strong_ntlm_policy=StrongNTLMPolicy[strong_ntlm_policy.upper()],
|
||||
user_allow_ntlm_auth=useropts.allow_ntlm_auth,
|
||||
user_tgt_lifetime=useropts.tgt_lifetime,
|
||||
user_allowed_to_authenticate_from=useropts.allowed_to_authenticate_from,
|
||||
user_allowed_to_authenticate_to=useropts.allowed_to_authenticate_to,
|
||||
service_allow_ntlm_auth=serviceopts.allow_ntlm_auth,
|
||||
service_tgt_lifetime=serviceopts.tgt_lifetime,
|
||||
service_allowed_to_authenticate_from=serviceopts.allowed_to_authenticate_from,
|
||||
service_allowed_to_authenticate_to=serviceopts.allowed_to_authenticate_to,
|
||||
computer_tgt_lifetime=computeropts.tgt_lifetime,
|
||||
computer_allowed_to_authenticate_to=computeropts.allowed_to_authenticate_to,
|
||||
)
|
||||
|
||||
# Either --enforce will be set or --audit but never both.
|
||||
# The default if both are missing is enforce=True.
|
||||
if enforce is not None:
|
||||
policy.enforced = enforce
|
||||
else:
|
||||
policy.enforced = not audit
|
||||
|
||||
# Create policy.
|
||||
try:
|
||||
policy.save(ldb)
|
||||
|
||||
if protect:
|
||||
policy.protect(ldb)
|
||||
except ModelError as e:
|
||||
raise CommandError(e)
|
||||
|
||||
# Authentication policy created successfully.
|
||||
print(f"Created authentication policy: {name}", file=self.outf)
|
||||
|
||||
|
||||
class cmd_domain_auth_policy_modify(Command):
|
||||
"""Modify authentication policies on the domain."""
|
||||
|
||||
synopsis = "%prog -H <URL> [options]"
|
||||
|
||||
takes_optiongroups = {
|
||||
"sambaopts": options.SambaOptions,
|
||||
"credopts": options.CredentialsOptions,
|
||||
"hostopts": options.HostOptions,
|
||||
"useropts": UserOptions,
|
||||
"serviceopts": ServiceOptions,
|
||||
"computeropts": ComputerOptions,
|
||||
}
|
||||
|
||||
takes_options = [
|
||||
Option("--name", help="Name of authentication policy (required).",
|
||||
dest="name", action="store", type=str, required=True),
|
||||
Option("--description",
|
||||
help="Optional description for authentication policy.",
|
||||
dest="description", action="store", type=str),
|
||||
Option("--protect",
|
||||
help="Protect authentication silo from accidental deletion.",
|
||||
dest="protect", action="store_true"),
|
||||
Option("--unprotect",
|
||||
help="Unprotect authentication silo from accidental deletion.",
|
||||
dest="unprotect", action="store_true"),
|
||||
Option("--audit",
|
||||
help="Only audit authentication policy.",
|
||||
dest="audit", action="store_true"),
|
||||
Option("--enforce",
|
||||
help="Enforce authentication policy.",
|
||||
dest="enforce", action="store_true"),
|
||||
Option("--strong-ntlm-policy",
|
||||
help=f"Strong NTLM Policy ({StrongNTLMPolicy.choices_str()}).",
|
||||
dest="strong_ntlm_policy", type="choice", action="store",
|
||||
choices=StrongNTLMPolicy.get_choices()),
|
||||
]
|
||||
|
||||
def run(self, hostopts=None, sambaopts=None, credopts=None, useropts=None,
|
||||
serviceopts=None, computeropts=None, name=None, description=None,
|
||||
protect=None, unprotect=None, audit=None, enforce=None,
|
||||
strong_ntlm_policy=None):
|
||||
|
||||
if protect and unprotect:
|
||||
raise CommandError("--protect and --unprotect cannot be used together.")
|
||||
if audit and enforce:
|
||||
raise CommandError("--audit and --enforce cannot be used together.")
|
||||
|
||||
# Check for repeated, similar arguments.
|
||||
check_similar_args("--user-allowed-to-authenticate-from",
|
||||
[useropts.allowed_to_authenticate_from,
|
||||
useropts.allowed_to_authenticate_from_device_group,
|
||||
useropts.allowed_to_authenticate_from_device_silo])
|
||||
check_similar_args("--user-allowed-to-authenticate-to",
|
||||
[useropts.allowed_to_authenticate_to,
|
||||
useropts.allowed_to_authenticate_to_by_group,
|
||||
useropts.allowed_to_authenticate_to_by_silo])
|
||||
check_similar_args("--service-allowed-to-authenticate-from",
|
||||
[serviceopts.allowed_to_authenticate_from,
|
||||
serviceopts.allowed_to_authenticate_from_device_group,
|
||||
serviceopts.allowed_to_authenticate_from_device_silo])
|
||||
check_similar_args("--service-allowed-to-authenticate-to",
|
||||
[serviceopts.allowed_to_authenticate_to,
|
||||
serviceopts.allowed_to_authenticate_to_by_group,
|
||||
serviceopts.allowed_to_authenticate_to_by_silo])
|
||||
check_similar_args("--computer-allowed-to-authenticate-to",
|
||||
[computeropts.allowed_to_authenticate_to,
|
||||
computeropts.allowed_to_authenticate_to_by_group,
|
||||
computeropts.allowed_to_authenticate_to_by_silo])
|
||||
|
||||
ldb = self.ldb_connect(hostopts, sambaopts, credopts)
|
||||
|
||||
# Generate SDDL for authenticating users from a device in a group
|
||||
if useropts.allowed_to_authenticate_from_device_group:
|
||||
group = Group.get(
|
||||
ldb, cn=useropts.allowed_to_authenticate_from_device_group)
|
||||
useropts.allowed_to_authenticate_from = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating users from a device in a silo
|
||||
if useropts.allowed_to_authenticate_from_device_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=useropts.allowed_to_authenticate_from_device_silo)
|
||||
useropts.allowed_to_authenticate_from = silo.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating user accounts to a group
|
||||
if useropts.allowed_to_authenticate_to_by_group:
|
||||
group = Group.get(
|
||||
ldb, cn=useropts.allowed_to_authenticate_to_by_group)
|
||||
useropts.allowed_to_authenticate_to = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating user accounts to a silo
|
||||
if useropts.allowed_to_authenticate_to_by_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=useropts.allowed_to_authenticate_to_by_silo)
|
||||
useropts.allowed_to_authenticate_to = silo.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating users from a device a device in a group
|
||||
if serviceopts.allowed_to_authenticate_from_device_group:
|
||||
group = Group.get(
|
||||
ldb, cn=serviceopts.allowed_to_authenticate_from_device_group)
|
||||
serviceopts.allowed_to_authenticate_from = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating service accounts from a device in a silo
|
||||
if serviceopts.allowed_to_authenticate_from_device_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=serviceopts.allowed_to_authenticate_from_device_silo)
|
||||
serviceopts.allowed_to_authenticate_from = silo.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating service accounts to a group
|
||||
if serviceopts.allowed_to_authenticate_to_by_group:
|
||||
group = Group.get(
|
||||
ldb, cn=serviceopts.allowed_to_authenticate_to_by_group)
|
||||
serviceopts.allowed_to_authenticate_to = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating service accounts to a silo
|
||||
if serviceopts.allowed_to_authenticate_to_by_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=serviceopts.allowed_to_authenticate_to_by_silo)
|
||||
serviceopts.allowed_to_authenticate_to = silo.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating computer accounts to a group
|
||||
if computeropts.allowed_to_authenticate_to_by_group:
|
||||
group = Group.get(
|
||||
ldb, cn=computeropts.allowed_to_authenticate_to_by_group)
|
||||
computeropts.allowed_to_authenticate_to = group.get_authentication_sddl()
|
||||
|
||||
# Generate SDDL for authenticating computer accounts to a silo
|
||||
if computeropts.allowed_to_authenticate_to_by_silo:
|
||||
silo = AuthenticationSilo.get(
|
||||
ldb, cn=computeropts.allowed_to_authenticate_to_by_silo)
|
||||
computeropts.allowed_to_authenticate_to = silo.get_authentication_sddl()
|
||||
|
||||
try:
|
||||
policy = AuthenticationPolicy.get(ldb, cn=name)
|
||||
except ModelError as e:
|
||||
raise CommandError(e)
|
||||
|
||||
# Check if authentication policy exists.
|
||||
if policy is None:
|
||||
raise CommandError(f"Authentication policy {name} not found.")
|
||||
|
||||
# Either --enforce will be set or --audit but never both.
|
||||
if enforce:
|
||||
policy.enforced = True
|
||||
elif audit:
|
||||
policy.enforced = False
|
||||
|
||||
# Update the description.
|
||||
if description is not None:
|
||||
policy.description = description
|
||||
|
||||
# User sign on
|
||||
###############
|
||||
|
||||
if strong_ntlm_policy is not None:
|
||||
policy.strong_ntlm_policy = \
|
||||
StrongNTLMPolicy[strong_ntlm_policy.upper()]
|
||||
|
||||
if useropts.tgt_lifetime is not None:
|
||||
policy.user_tgt_lifetime = useropts.tgt_lifetime
|
||||
|
||||
if useropts.allowed_to_authenticate_from is not None:
|
||||
policy.user_allowed_to_authenticate_from = \
|
||||
useropts.allowed_to_authenticate_from
|
||||
|
||||
if useropts.allowed_to_authenticate_to is not None:
|
||||
policy.user_allowed_to_authenticate_to = \
|
||||
useropts.allowed_to_authenticate_to
|
||||
|
||||
# Service sign on
|
||||
##################
|
||||
|
||||
if serviceopts.tgt_lifetime is not None:
|
||||
policy.service_tgt_lifetime = serviceopts.tgt_lifetime
|
||||
|
||||
if serviceopts.allowed_to_authenticate_from is not None:
|
||||
policy.service_allowed_to_authenticate_from = \
|
||||
serviceopts.allowed_to_authenticate_from
|
||||
|
||||
if serviceopts.allowed_to_authenticate_to is not None:
|
||||
policy.service_allowed_to_authenticate_to = \
|
||||
serviceopts.allowed_to_authenticate_to
|
||||
|
||||
# Computer
|
||||
###########
|
||||
|
||||
if computeropts.tgt_lifetime is not None:
|
||||
policy.computer_tgt_lifetime = computeropts.tgt_lifetime
|
||||
|
||||
if computeropts.allowed_to_authenticate_to is not None:
|
||||
policy.computer_allowed_to_authenticate_to = \
|
||||
computeropts.allowed_to_authenticate_to
|
||||
|
||||
# Update policy.
|
||||
try:
|
||||
policy.save(ldb)
|
||||
|
||||
if protect:
|
||||
policy.protect(ldb)
|
||||
elif unprotect:
|
||||
policy.unprotect(ldb)
|
||||
except ModelError as e:
|
||||
raise CommandError(e)
|
||||
|
||||
# Authentication policy updated successfully.
|
||||
print(f"Updated authentication policy: {name}", file=self.outf)
|
||||
|
||||
|
||||
class cmd_domain_auth_policy_delete(Command):
|
||||
"""Delete authentication policies on the domain."""
|
||||
|
||||
synopsis = "%prog -H <URL> [options]"
|
||||
|
||||
takes_optiongroups = {
|
||||
"sambaopts": options.SambaOptions,
|
||||
"credopts": options.CredentialsOptions,
|
||||
"hostopts": options.HostOptions,
|
||||
}
|
||||
|
||||
takes_options = [
|
||||
Option("--name", help="Name of authentication policy (required).",
|
||||
dest="name", action="store", type=str, required=True),
|
||||
Option("--force", help="Force delete protected authentication policy.",
|
||||
dest="force", action="store_true")
|
||||
]
|
||||
|
||||
def run(self, hostopts=None, sambaopts=None, credopts=None, name=None,
|
||||
force=None):
|
||||
|
||||
ldb = self.ldb_connect(hostopts, sambaopts, credopts)
|
||||
|
||||
try:
|
||||
policy = AuthenticationPolicy.get(ldb, cn=name)
|
||||
except ModelError as e:
|
||||
raise CommandError(e)
|
||||
|
||||
# Check if authentication policy exists first.
|
||||
if policy is None:
|
||||
raise CommandError(f"Authentication policy {name} not found.")
|
||||
|
||||
# Delete item, --force removes delete protection first.
|
||||
try:
|
||||
if force:
|
||||
policy.unprotect(ldb)
|
||||
|
||||
policy.delete(ldb)
|
||||
except ModelError as e:
|
||||
if not force:
|
||||
raise CommandError(
|
||||
f"{e}\nTry --force to delete protected authentication policies.")
|
||||
else:
|
||||
raise CommandError(e)
|
||||
|
||||
# Authentication policy deleted successfully.
|
||||
print(f"Deleted authentication policy: {name}", file=self.outf)
|
Loading…
Reference in New Issue
Block a user