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

NAS-132078 / 25.04 / refactor kerberos plugin to use api_method #14808

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions src/middlewared/middlewared/api/v25_04_0/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from .acme_protocol import * # noqa
from .acl import * # noqa
from .activedirectory import * # noqa
from .alert import * # noqa
from .alertservice import * # noqa
from .api_key import * # noqa
Expand All @@ -13,6 +14,9 @@
from .fcport import * # noqa
from .group import * # noqa
from .iscsi_auth import * # noqa
from .kerberos import * # noqa
from .kerberos_keytab import * # noqa
from .kerberos_realm import * # noqa
from .keychain import * # noqa
from .privilege import * # noqa
from .rdma import * # noqa
Expand Down
28 changes: 28 additions & 0 deletions src/middlewared/middlewared/api/v25_04_0/activedirectory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from middlewared.api.base import (
BaseModel,
NonEmptyString,
single_argument_args,
)
from middlewared.utils.directoryservices.krb5_constants import (
krb5ccache,
)
from pydantic import Field, Secret
from typing import Literal


__all__ = [
'ActivedirectoryLeaveArgs', 'ActivedirectoryLeaveResult',
]


class ActivedirectoryUsernamePassword(BaseModel):
username: NonEmptyString
password: Secret[NonEmptyString]


class ActivedirectoryLeaveArgs(BaseModel):
ad_cred: ActivedirectoryUsernamePassword


class ActivedirectoryLeaveResult(BaseModel):
result: Literal[True]
156 changes: 156 additions & 0 deletions src/middlewared/middlewared/api/v25_04_0/kerberos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
from middlewared.api.base import (
BaseModel,
NonEmptyString,
single_argument_args,
)
from middlewared.utils.directoryservices.krb5_constants import (
krb5ccache,
)
from pydantic import Field, Secret
from typing import Literal


__all__ = [
'KerberosKdestroyArgs', 'KerberosKdestroyResult',
'KerberosKinitArgs', 'KerberosKinitResult',
'KerberosKlistArgs', 'KerberosKlistResult',
'KerberosCheckTicketArgs', 'KerberosCheckTicketResult',
'KerberosGetCredArgs', 'KerberosGetCredResult',
]


class KerberosCredentialUsernamePassword(BaseModel):
""" Private API entry defined for normalization purposes """
username: NonEmptyString
password: Secret[NonEmptyString]


class KerberosCredentialKeytab(BaseModel):
""" Private API entry defined for normalization purposes """
kerberos_principal: NonEmptyString


class KerberosCcacheOptions(BaseModel):
""" Private API entry defined for normalization purposes """
ccache: Literal[
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could consider ccache: krb5ccache = krb5ccache.SYSTEM as long as we handle the enum fields properly in the endpoints.

krb5ccache.SYSTEM.value,
krb5ccache.TEMP.value,
krb5ccache.USER.value,
] = krb5ccache.SYSTEM.value
cache_uid: int = 0


class KerberosKinitKdcOverride(BaseModel):
""" Private API entry defined for normalization purposes """
domain: str | None = None
kdc: str | None = None
libdefaults_aux: list[str] | None = None


class KerberosKinitOptions(KerberosCcacheOptions):
""" Private API entry defined for normalization purposes """
renewal_period: int = 7
lifetime: int = 0
kdc_override: KerberosKinitKdcOverride = Field(default=KerberosKinitKdcOverride())


class KerberosKlistOptions(KerberosCcacheOptions):
""" Private API entry defined for normalization purposes """
timeout: int = 10


@single_argument_args('kerberos_kinit')
class KerberosKinitArgs(BaseModel):
""" Private API entry defined for normalization purposes """
krb5_cred: KerberosCredentialUsernamePassword | KerberosCredentialKeytab
kinit_options: KerberosKinitOptions = Field(alias='kinit-options', default=KerberosKinitOptions())


class KerberosKinitResult(BaseModel):
""" Private API entry defined for normalization purposes """
result: Literal[None]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

result: None suffices



class KerberosKlistArgs(BaseModel):
""" Private API entry defined for normalization purposes """
klist_options: KerberosKlistOptions


class KerberosKlistEntry(BaseModel):
""" Private API entry defined for normalization purposes """
issued: int
expires: int
renew_until: int
client: NonEmptyString
server: NonEmptyString
etype: NonEmptyString
flags: list[str]


class KerberosKlistFull(BaseModel):
""" Private API entry defined for normalization purposes """
default_principal: NonEmptyString
ticket_cache: NonEmptyString
tickets: list[KerberosKlistEntry]


class KerberosKlistResult(BaseModel):
""" Private API entry defined for normalization purposes """
result: KerberosKlistFull


class KerberosKdestroyArgs(KerberosCcacheOptions):
""" Private API entry defined for normalization purposes """
pass


class KerberosKdestroyResult(BaseModel):
""" Private API entry defined for normalization purposes """
result: Literal[None]


class KerberosCheckTicketArgs(BaseModel):
""" Private API entry defined for normalization purposes """
kerberos_options: KerberosCcacheOptions = Field(alias='kerberos-options', default=KerberosCcacheOptions())
raise_error: bool = True


class KerberosGssCred(BaseModel):
""" Private API entry defined for normalization purposes """
name: NonEmptyString
name_type: NonEmptyString
name_type_oid: str
lifetime: int


class KerberosCheckTicketResult(BaseModel):
""" Private API entry defined for normalization purposes """
result: KerberosGssCred


class ADKinitParameters(BaseModel):
""" Private API entry defined for normalization purposes """
bindname: NonEmptyString
bindpw: Secret[NonEmptyString]
domainname: NonEmptyString
kerberos_principal: NonEmptyString


class LDAPKinitParameters(BaseModel):
""" Private API entry defined for normalization purposes """
binddn: NonEmptyString | None
bindpw: Secret[NonEmptyString | None]
kerberos_realm: int
kerberos_principal: str | None


@single_argument_args('kerberos_get_cred')
class KerberosGetCredArgs(BaseModel):
""" Private API entry defined for normalization purposes """
ds_type: Literal['ACTIVEDIRECTORY', 'LDAP', 'IPA']
conf: ADKinitParameters | LDAPKinitParameters


class KerberosGetCredResult(BaseModel):
""" Private API entry defined for normalization purposes """
result: KerberosCredentialUsernamePassword | KerberosCredentialKeytab
56 changes: 56 additions & 0 deletions src/middlewared/middlewared/api/v25_04_0/kerberos_keytab.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from middlewared.api.base import (
BaseModel,
Excluded,
excluded_field,
ForUpdateMetaclass,
NonEmptyString,
)
from pydantic import Secret
from typing import Literal


__all__ = [
'KerberosKeytabEntry',
'KerberosKeytabCreateArgs', 'KerberosKeytabCreateResult',
'KerberosKeytabUpdateArgs', 'KerberosKeytabUpdateResult',
'KerberosKeytabDeleteArgs', 'KerberosKeytabDeleteResult',
]


class KerberosKeytabEntry(BaseModel):
id: int
file: Secret[NonEmptyString]
name: NonEmptyString


class KerberosKeytabCreate(KerberosKeytabEntry):
id: Excluded = excluded_field()


class KerberosKeytabUpdate(KerberosKeytabCreate, metaclass=ForUpdateMetaclass):
pass


class KerberosKeytabCreateArgs(BaseModel):
kerberos_keytab_create: KerberosKeytabCreate


class KerberosKeytabUpdateArgs(BaseModel):
id: int
kerberos_keytab_update: KerberosKeytabUpdate


class KerberosKeytabCreateResult(BaseModel):
result: KerberosKeytabEntry


class KerberosKeytabUpdateResult(BaseModel):
result: KerberosKeytabEntry


class KerberosKeytabDeleteArgs(BaseModel):
id: int


class KerberosKeytabDeleteResult(BaseModel):
result: Literal[True]
57 changes: 57 additions & 0 deletions src/middlewared/middlewared/api/v25_04_0/kerberos_realm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from middlewared.api.base import (
BaseModel,
Excluded,
excluded_field,
ForUpdateMetaclass,
NonEmptyString,
)
from typing import Literal


__all__ = [
'KerberosRealmEntry',
'KerberosRealmCreateArgs', 'KerberosRealmCreateResult',
'KerberosRealmUpdateArgs', 'KerberosRealmUpdateResult',
'KerberosRealmDeleteArgs', 'KerberosRealmDeleteResult',
]


class KerberosRealmEntry(BaseModel):
id: int
realm: NonEmptyString
kdc: list[str]
admin_server: list[str]
kpasswd_server: list[str]


class KerberosRealmCreate(KerberosRealmEntry):
id: Excluded = excluded_field()


class KerberosRealmUpdate(KerberosRealmCreate, metaclass=ForUpdateMetaclass):
pass


class KerberosRealmCreateArgs(BaseModel):
kerberos_realm_create: KerberosRealmCreate


class KerberosRealmUpdateArgs(BaseModel):
id: int
kerberos_realm_update: KerberosRealmUpdate


class KerberosRealmCreateResult(BaseModel):
result: KerberosRealmEntry


class KerberosRealmUpdateResult(BaseModel):
result: KerberosRealmEntry


class KerberosRealmDeleteArgs(BaseModel):
id: int


class KerberosRealmDeleteResult(BaseModel):
result: Literal[True]
13 changes: 10 additions & 3 deletions src/middlewared/middlewared/plugins/activedirectory.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
import os
import contextlib

from middlewared.api import api_method
from middlewared.api.current import (
ActivedirectoryLeaveArgs, ActivedirectoryLeaveResult,
)
from middlewared.plugins.smb import SMBCmd
from middlewared.plugins.kerberos import krb5ccache
from middlewared.schema import (
Expand Down Expand Up @@ -776,8 +780,11 @@ async def lookup_dc(self, domain=None):
out = json.loads(lookup.stdout.decode())
return out

@accepts(Ref('kerberos_username_password'), roles=['DIRECTORY_SERVICE_WRITE'], audit='Active directory leave')
@returns()
@api_method(
ActivedirectoryLeaveArgs, ActivedirectoryLeaveResult,
roles=['DIRECTORY_SERVICE_WRITE'],
audit='Active directory leave',
)
@job(lock="AD_start_stop")
async def leave(self, job, data):
"""
Expand Down Expand Up @@ -880,4 +887,4 @@ async def leave(self, job, data):
await self.middleware.call('service.restart', 'cifs')
await self.middleware.call('service.restart', 'idmap')
job.set_progress(100, 'Successfully left activedirectory domain.')
return
return True
Loading
Loading