|
14 | 14 | from ai.backend.common.resilience.policies.metrics import MetricArgs, MetricPolicy |
15 | 15 | from ai.backend.common.resilience.policies.retry import BackoffStrategy, RetryArgs, RetryPolicy |
16 | 16 | from ai.backend.common.resilience.resilience import Resilience |
17 | | -from ai.backend.manager.data.auth.types import GroupMembershipData, UserData |
| 17 | +from ai.backend.manager.data.auth.types import CredentialData, GroupMembershipData, UserData |
18 | 18 | from ai.backend.manager.errors.auth import GroupMembershipNotFoundError, UserCreationError |
19 | 19 | from ai.backend.manager.models.group import association_groups_users, groups |
20 | 20 | from ai.backend.manager.models.hasher.types import PasswordInfo |
21 | | -from ai.backend.manager.models.keypair import keypairs |
| 21 | +from ai.backend.manager.models.keypair import KeyPairRow, keypairs |
22 | 22 | from ai.backend.manager.models.user import ( |
23 | 23 | UserRow, |
24 | 24 | UserStatus, |
@@ -285,3 +285,43 @@ async def fetch_current_time(self) -> datetime: |
285 | 285 | """Fetch current time from database.""" |
286 | 286 | async with self._db.begin_readonly() as db_conn: |
287 | 287 | return await db_conn.scalar(sa.select(sa.func.now())) |
| 288 | + |
| 289 | + @auth_db_source_resilience.apply() |
| 290 | + async def fetch_credential_by_access_key(self, access_key: str) -> Optional[CredentialData]: |
| 291 | + """ |
| 292 | + Fetch user credential data by access key. |
| 293 | +
|
| 294 | + Queries keypair with user and resource policies using ORM relationships. |
| 295 | + Returns None if access key not found or inactive. |
| 296 | +
|
| 297 | + Args: |
| 298 | + access_key: The access key to look up. |
| 299 | +
|
| 300 | + Returns: |
| 301 | + CredentialData containing user, keypair, and resource policies, |
| 302 | + or None if not found. |
| 303 | + """ |
| 304 | + async with self._db.begin_session() as db_session: |
| 305 | + query = ( |
| 306 | + sa.select(KeyPairRow) |
| 307 | + .where((KeyPairRow.access_key == access_key) & (KeyPairRow.is_active.is_(True))) |
| 308 | + .options( |
| 309 | + joinedload(KeyPairRow.resource_policy_row), |
| 310 | + joinedload(KeyPairRow.user_row).joinedload(UserRow.resource_policy_row), |
| 311 | + ) |
| 312 | + ) |
| 313 | + keypair_row = await db_session.scalar(query) |
| 314 | + |
| 315 | + if keypair_row is None: |
| 316 | + return None |
| 317 | + |
| 318 | + user_row = keypair_row.user_row |
| 319 | + if user_row is None: |
| 320 | + return None |
| 321 | + |
| 322 | + return CredentialData( |
| 323 | + user=user_row.to_data(), |
| 324 | + user_resource_policy=user_row.resource_policy_row.to_dataclass(), |
| 325 | + keypair=keypair_row.to_data(), |
| 326 | + keypair_resource_policy=keypair_row.resource_policy_row.to_dataclass(), |
| 327 | + ) |
0 commit comments