Skip to content

Commit f35eee2

Browse files
author
m.shvets
committed
Refactor: Update ObjectSID and RIDSet handling to use directory IDs instead of objects for improved consistency and performance
1 parent af14d05 commit f35eee2

19 files changed

+242
-189
lines changed

app/alembic/versions/552b4eafb1aa_remove_objectsid_vals.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Add rIDManager and rIDSet objectClasses to LDAP schema.
22
33
Revision ID: 552b4eafb1aa
4-
Revises: 19d86e660cf2
4+
Revises: df4287898910
55
Create Date: 2026-02-17 09:24:57.906080
66
77
"""
@@ -230,10 +230,11 @@ async def _init_rid_manager(
230230
if rid > max_rid:
231231
max_rid = rid
232232

233-
start_rid = max(max_rid, RIDManagerSetupUseCase.RID_USER_MIN)
233+
start_rid = max(max_rid, RIDManagerSetupUseCase.RID_MIN)
234234

235235
qword = to_qword(start_rid, RIDManagerSetupUseCase.RID_AVAILABLE_MAX)
236-
await rid_setup_gateway.set_rid_available_pool(domain, qword)
236+
237+
await rid_setup_gateway.set_rid_available_pool(rid_manager_dir, qword)
237238

238239
system_container = await rid_setup_gateway.get_system_container()
239240
await role_use_case.inherit_parent_aces(

app/alembic/versions/a1b2c3d4e5f6_rename_services_to_system.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from sqlalchemy import select
1212
from sqlalchemy.ext.asyncio import AsyncConnection, AsyncSession
1313

14+
from constants import SYSTEM_CONTAINER_NAME
1415
from entities import Attribute, Directory
1516
from repo.pg.tables import queryable_attr as qa
1617

@@ -111,7 +112,7 @@ async def _rename_system_to_services(connection: AsyncConnection) -> None: # no
111112

112113
system_dir = await session.scalar(
113114
select(Directory).where(
114-
qa(Directory.name) == "System",
115+
qa(Directory.name) == SYSTEM_CONTAINER_NAME,
115116
qa(Directory.is_system).is_(True),
116117
),
117118
)

app/enums.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,10 +293,7 @@ class SidPrefix(StrEnum):
293293
class SecurityPrincipalRid(IntEnum):
294294
ADMINISTRATOR = 500
295295
GUESTS = 501
296-
KRBTGT = 502
297296
DOMAIN_ADMINS = 512
298297
DOMAIN_USERS = 513
299-
DOMAIN_GUESTS = 514
300298
DOMAIN_COMPUTERS = 515
301-
DOMAIN_CONTROLLERS = 516
302299
DOMAIN_READ_ONLY = 521

app/extra/scripts/add_domain_controller.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
EntityTypeUseCase,
1717
)
1818
from ldap_protocol.objects import UserAccountControlFlag
19-
from ldap_protocol.rid_manager import ObjectSIDUseCase
19+
from ldap_protocol.rid_manager import ObjectSIDUseCase, RIDSetUseCase
2020
from ldap_protocol.roles.role_use_case import RoleUseCase
2121
from repo.pg.tables import queryable_attr as qa
2222

@@ -28,6 +28,7 @@ async def _add_domain_controller(
2828
settings: Settings,
2929
dc_ou_dir: Directory,
3030
object_sid_use_case: ObjectSIDUseCase,
31+
rid_set_use_case: RIDSetUseCase,
3132
) -> None:
3233
dc_directory = Directory(
3334
object_class="",
@@ -40,9 +41,13 @@ async def _add_domain_controller(
4041

4142
dc_directory.parent_id = dc_ou_dir.id
4243
await object_sid_use_case.add(
43-
directory=dc_directory,
44+
directory_id=dc_directory.id,
4445
)
4546
await session.flush()
47+
await rid_set_use_case.add(
48+
domain_controller=dc_directory,
49+
allocation_params=await rid_set_use_case.generate_rid_set_attrs(),
50+
)
4651

4752
attributes = [
4853
Attribute(
@@ -105,6 +110,7 @@ async def add_domain_controller(
105110
role_use_case: RoleUseCase,
106111
entity_type_use_case: EntityTypeUseCase,
107112
object_sid_use_case: ObjectSIDUseCase,
113+
rid_set_use_case: RIDSetUseCase,
108114
) -> None:
109115
logger.info("Adding domain controller.")
110116

@@ -139,6 +145,7 @@ async def add_domain_controller(
139145
settings=settings,
140146
dc_ou_dir=domain_controllers_ou,
141147
object_sid_use_case=object_sid_use_case,
148+
rid_set_use_case=rid_set_use_case,
142149
)
143150

144151
logger.debug("Domain controller added.")

app/ldap_protocol/auth/setup_gateway.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ async def setup_enviroment(
7373
) -> None:
7474
"""Create directories and users for enviroment."""
7575
async with self._session.begin_nested():
76-
self._session.add(domain)
7776
self._session.add(
7877
NetworkPolicy(
7978
name="Default open policy",
@@ -122,14 +121,6 @@ async def setup_enviroment(
122121
logger.error(traceback.format_exc())
123122
raise
124123

125-
async def is_base_domain_created(self) -> bool:
126-
"""Check if base domain is created."""
127-
cat_result = await self._session.execute(select(Directory))
128-
if cat_result.scalar_one_or_none():
129-
logger.warning("dev data already set up")
130-
return True
131-
return False
132-
133124
async def create_base_domain(
134125
self,
135126
dn: str = "multifactor.dev",
@@ -175,7 +166,7 @@ async def create_dir(
175166

176167
if "objectSid" in data:
177168
await self._object_sid_use_case.add(
178-
directory=dir_,
169+
directory_id=dir_.id,
179170
rid=int(data["objectSid"]),
180171
sid_prefix=SidPrefix.BUILT_IN_DOMAIN,
181172
)

app/ldap_protocol/auth/use_cases.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,6 @@ async def _create(self, dto: SetupDTO, data: list) -> None:
210210
:return: None.
211211
"""
212212
try:
213-
if await self._setup_gateway.is_base_domain_created():
214-
return
215213
domain = await self._setup_gateway.create_base_domain(dto.domain)
216214
await self._rid_manager_setup_use_case.create_domain_identifier()
217215
await self._setup_gateway.setup_enviroment(
@@ -255,7 +253,7 @@ async def _create(self, dto: SetupDTO, data: list) -> None:
255253
await self._rid_manager_setup_use_case.setup()
256254
dc = await self._rid_manager_use_case.get_domain_controller()
257255
await self._object_sid_use_case.add(
258-
directory=dc,
256+
directory_id=dc.id,
259257
)
260258

261259
await self._session.commit()

app/ldap_protocol/ldap_requests/add.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ def from_data(cls, data: ASN1Row) -> "AddRequest":
104104
type=attr.value[0].value,
105105
vals=[val.value for val in attr.value[1].value],
106106
)
107-
for attr in attributes.value # type: ignore
107+
for attr in attributes.value
108108
]
109-
return cls(entry=entry.value, attributes=attributes) # type: ignore
109+
return cls(entry=entry.value, attributes=attributes)
110110

111111
async def handle( # noqa: C901
112112
self,
@@ -214,7 +214,7 @@ async def handle( # noqa: C901
214214

215215
await ctx.session.flush()
216216
await ctx.object_sid_use_case.add(
217-
directory=new_dir,
217+
directory_id=new_dir.id,
218218
)
219219
await ctx.session.flush()
220220
except IntegrityError:

app/ldap_protocol/rid_manager/object_sid_gateway.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
from sqlalchemy import select
88
from sqlalchemy.ext.asyncio import AsyncSession
99

10-
from entities import Attribute, Directory
10+
from entities import Attribute
1111
from ldap_protocol.rid_manager.exceptions import (
1212
RIDManagerDomainIdentifierNotFoundError,
1313
RIDManagerObjectSIDNotFoundError,
1414
)
15+
from ldap_protocol.utils.async_cache import domain_identifier_cache
1516
from repo.pg.tables import queryable_attr as qa
1617

1718

@@ -22,11 +23,11 @@ def __init__(self, session: AsyncSession) -> None:
2223
"""Initialize Object SID gateway."""
2324
self._session = session
2425

25-
async def get(self, directory: Directory) -> str:
26+
async def get(self, directory_id: int) -> str:
2627
"""Get object SID."""
2728
query = await self._session.scalar(
2829
select(Attribute).where(
29-
qa(Attribute.directory_id) == directory.id,
30+
qa(Attribute.directory_id) == directory_id,
3031
qa(Attribute.name) == "objectSid",
3132
),
3233
)
@@ -35,25 +36,26 @@ async def get(self, directory: Directory) -> str:
3536

3637
return query.value
3738

38-
async def add(self, directory: Directory, object_sid: str) -> None:
39+
async def add(self, directory_id: int, object_sid: str) -> None:
3940
"""Add object SID."""
4041
self._session.add(
4142
Attribute(
4243
name="objectSid",
4344
value=object_sid,
44-
directory_id=directory.id,
45+
directory_id=directory_id,
4546
),
4647
)
4748

48-
async def get_domain_identifier(self, domain: Directory) -> str:
49-
"""Get domain identifier.
49+
async def get_domain_identifier(self) -> str:
50+
"""Get domain identifier (cached ``Attribute.value`` string)."""
51+
return await domain_identifier_cache.get_or_load(
52+
self._load_domain_identifier_value,
53+
)
5054

51-
:return: Domain identifier
52-
"""
55+
async def _load_domain_identifier_value(self) -> str:
5356
query = await self._session.scalar(
5457
select(Attribute).where(
5558
qa(Attribute.name) == "DomainIdentifier",
56-
qa(Attribute.directory_id) == domain.id,
5759
),
5860
)
5961

app/ldap_protocol/rid_manager/object_sid_use_case.py

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@
66

77
from sqlalchemy.ext.asyncio import AsyncSession
88

9-
from entities import Directory
109
from enums import SidPrefix
1110
from ldap_protocol.rid_manager.object_sid_gateway import ObjectSIDGateway
1211
from ldap_protocol.rid_manager.rid_manager_use_case import RIDManagerUseCase
1312
from ldap_protocol.rid_manager.rid_set_use_case import RIDSetUseCase
14-
from ldap_protocol.utils.queries import get_base_directories
1513

1614

1715
class ObjectSIDUseCase:
@@ -30,13 +28,13 @@ def __init__(
3028
self._session = session
3129
self._rid_manager_use_case = rid_manager_use_case
3230

33-
async def get(self, directory: Directory) -> str:
31+
async def get(self, directory_id: int) -> str:
3432
"""Get object SID."""
35-
return await self._gateway.get(directory)
33+
return await self._gateway.get(directory_id)
3634

3735
async def add(
3836
self,
39-
directory: Directory,
37+
directory_id: int,
4038
rid: int | None = None,
4139
sid_prefix: SidPrefix = SidPrefix.DOMAIN_IDENTIFIER,
4240
) -> None:
@@ -47,19 +45,13 @@ async def add(
4745
)
4846
rid_set = await self._rid_set_use_case.get(domain_controller)
4947
rid = await self._rid_set_use_case.allocate_next_rid(
50-
rid_set,
48+
rid_set.id,
5149
)
5250

5351
if sid_prefix == SidPrefix.BUILT_IN_DOMAIN:
5452
object_sid = f"{sid_prefix}-{rid}"
5553
elif sid_prefix == SidPrefix.DOMAIN_IDENTIFIER:
56-
domain_identifier = await self.get_domain_identifier()
54+
domain_identifier = await self._gateway.get_domain_identifier()
5755
object_sid = f"{sid_prefix}-{domain_identifier}-{rid}"
5856

59-
await self._gateway.add(directory, object_sid)
60-
61-
async def get_domain_identifier(self) -> str:
62-
"""Get domain identifier."""
63-
domain = (await get_base_directories(self._session))[0]
64-
65-
return await self._gateway.get_domain_identifier(domain)
57+
await self._gateway.add(directory_id, object_sid)

app/ldap_protocol/rid_manager/rid_manager_gateway.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from sqlalchemy.ext.asyncio import AsyncSession
99

1010
from config import Settings
11+
from constants import DOMAIN_CONTROLLERS_OU_NAME
1112
from entities import Attribute, Directory
1213
from ldap_protocol.rid_manager.exceptions import (
1314
RIDManagerAvailablePoolNotFoundError,
@@ -59,9 +60,32 @@ async def get_domain_controller(
5960
self,
6061
) -> Directory:
6162
"""Get domain controller."""
63+
domain = await self._session.scalar(
64+
select(Directory).where(
65+
qa(Directory.object_class) == "domain",
66+
qa(Directory.parent_id).is_(None),
67+
),
68+
)
69+
if not domain:
70+
raise RIDManagerDomainControllerNotFoundError(
71+
"Domain controller not found",
72+
)
73+
74+
domain_controllers_ou = await self._session.scalar(
75+
select(Directory).where(
76+
qa(Directory.name) == DOMAIN_CONTROLLERS_OU_NAME,
77+
qa(Directory.parent_id) == domain.id,
78+
),
79+
)
80+
if not domain_controllers_ou:
81+
raise RIDManagerDomainControllerNotFoundError(
82+
"Domain controllers OU not found",
83+
)
84+
6285
domain_controller = await self._session.scalar(
6386
select(Directory).where(
6487
qa(Directory.name) == self._settings.HOST_MACHINE_SHORT_NAME,
88+
qa(Directory.parent_id) == domain_controllers_ou.id,
6589
),
6690
)
6791
if not domain_controller:

0 commit comments

Comments
 (0)