|
1 | 1 | import { |
2 | 2 | HOSTED_AUTH_HEADERS, |
3 | 3 | HOSTED_AUTH_ROUTES, |
4 | | - type HostedAuthStatus, |
5 | 4 | type HostedPrincipal, |
6 | 5 | parseOidcLoginAttemptId, |
7 | 6 | parseOpaqueAuthoritySecret, |
@@ -36,8 +35,14 @@ import { |
36 | 35 | SESSION_COOKIE, |
37 | 36 | } from '../../../../core/domain'; |
38 | 37 |
|
| 38 | +import { projectHostedAuthStatus } from './HostedAuthStatusProjection'; |
39 | 39 | import { applyHostedCapabilityAdvertisements } from './HostedCapabilityAdvertisement'; |
| 40 | +import { setHostedCredentialCookies as setCookies } from './HostedCredentialCookies'; |
40 | 41 | import { HostedEventStreamRequestFenceRegistry } from './HostedEventStreamRequestFence'; |
| 42 | +import { |
| 43 | + isHostedTeamWorkspaceAuthorized, |
| 44 | + isHostedTeamWorkspaceEventAuthorized, |
| 45 | +} from './HostedTeamWorkspaceEventAuthorization'; |
41 | 46 | import { |
42 | 47 | captureHostedTeamWorkspaceGrantFence, |
43 | 48 | type HostedRequestGrantFence, |
@@ -188,41 +193,32 @@ export class HostedAuthHttpController { |
188 | 193 | return context !== null && roleAllows(context.principal.role, 'hosted.query'); |
189 | 194 | } |
190 | 195 | async isTeamWorkspaceAuthorized(request: unknown, teamId: TeamId): Promise<boolean> { |
191 | | - const context = await this.liveRequestContext(request as HostedHttpRequest); |
192 | | - if (!context) return false; |
193 | | - return this.workspaceAccess |
194 | | - .hasTeamWorkspaceGrant( |
195 | | - context.principal.userId, |
196 | | - teamId, |
197 | | - this.dependencies.resolveTeamWorkspaceId |
198 | | - ) |
199 | | - .catch(() => false); |
| 196 | + return isHostedTeamWorkspaceAuthorized({ |
| 197 | + request: request as HostedHttpRequest, |
| 198 | + teamId, |
| 199 | + workspaceAccess: this.workspaceAccess, |
| 200 | + ...(this.dependencies.resolveTeamWorkspaceId === undefined |
| 201 | + ? {} |
| 202 | + : { resolveTeamWorkspaceId: this.dependencies.resolveTeamWorkspaceId }), |
| 203 | + liveRequestContext: (candidate) => this.liveRequestContext(candidate), |
| 204 | + }); |
200 | 205 | } |
201 | 206 | async isTeamWorkspaceEventAuthorized( |
202 | 207 | request: unknown, |
203 | 208 | teamId: TeamId, |
204 | 209 | runtimeWorkspaceId: string |
205 | 210 | ): Promise<boolean> { |
206 | 211 | const hostedRequest = request as HostedHttpRequest; |
207 | | - const context = await this.liveRequestContext(hostedRequest); |
208 | | - if (context === null || !roleAllows(context.principal.role, 'hosted.events')) return false; |
209 | | - try { |
210 | | - const fence = await this.workspaceAccess.captureTeamWorkspaceGrantFence( |
211 | | - context.principal.userId, |
212 | | - teamId, |
213 | | - this.dependencies.resolveTeamWorkspaceId |
214 | | - ); |
215 | | - return ( |
216 | | - fence !== null && |
217 | | - fence.runtimeWorkspaceId === runtimeWorkspaceId && |
218 | | - (await this.workspaceAccess.revalidateTeamWorkspaceGrantFence( |
219 | | - fence, |
220 | | - this.dependencies.resolveTeamWorkspaceId |
221 | | - )) |
222 | | - ); |
223 | | - } catch { |
224 | | - return false; |
225 | | - } |
| 212 | + return isHostedTeamWorkspaceEventAuthorized({ |
| 213 | + request: hostedRequest, |
| 214 | + teamId, |
| 215 | + runtimeWorkspaceId, |
| 216 | + workspaceAccess: this.workspaceAccess, |
| 217 | + ...(this.dependencies.resolveTeamWorkspaceId === undefined |
| 218 | + ? {} |
| 219 | + : { resolveTeamWorkspaceId: this.dependencies.resolveTeamWorkspaceId }), |
| 220 | + liveRequestContext: (candidate) => this.liveRequestContext(candidate), |
| 221 | + }); |
226 | 222 | } |
227 | 223 | async isHostedTaskMutationAuthorized(request: unknown, teamId?: TeamId): Promise<boolean> { |
228 | 224 | const hostedRequest = request as HostedHttpRequest; |
@@ -301,7 +297,7 @@ export class HostedAuthHttpController { |
301 | 297 | 'auth.personal.pair', |
302 | 298 | 'success' |
303 | 299 | ); |
304 | | - this.setCredentialCookies(reply, result.value.sessionSecret, result.value.deviceSecret); |
| 300 | + setCookies(reply, result.value.sessionSecret, result.value.deviceSecret, this.dependencies); |
305 | 301 | return this.status(result.value.principal, result.value.csrfToken); |
306 | 302 | } catch (error) { |
307 | 303 | const storageUnavailable = |
@@ -687,10 +683,11 @@ export class HostedAuthHttpController { |
687 | 683 | 'auth.personal.renew', |
688 | 684 | 'success' |
689 | 685 | ); |
690 | | - this.setCredentialCookies( |
| 686 | + setCookies( |
691 | 687 | reply, |
692 | 688 | result.context.sessionSecret, |
693 | | - result.replacementDeviceSecret |
| 689 | + result.replacementDeviceSecret, |
| 690 | + this.dependencies |
694 | 691 | ); |
695 | 692 | } |
696 | 693 | const context = result.context; |
@@ -757,34 +754,14 @@ export class HostedAuthHttpController { |
757 | 754 | (fetchSite === undefined || fetchSite === 'same-origin' || fetchSite === 'same-site') |
758 | 755 | ); |
759 | 756 | } |
760 | | - private setCredentialCookies( |
761 | | - reply: HostedHttpReply, |
762 | | - sessionSecret: string, |
763 | | - deviceSecret: string |
764 | | - ): void { |
765 | | - reply.header('set-cookie', [ |
766 | | - cookie(SESSION_COOKIE, sessionSecret, { |
767 | | - maxAge: this.dependencies.sessionMaxAgeSeconds, |
768 | | - secure: this.dependencies.secureCookies, |
769 | | - sameSite: 'Strict', |
770 | | - }), |
771 | | - cookie(DEVICE_COOKIE, deviceSecret, { |
772 | | - maxAge: this.dependencies.deviceMaxAgeSeconds, |
773 | | - secure: this.dependencies.secureCookies, |
774 | | - sameSite: 'Strict', |
775 | | - }), |
776 | | - ]); |
777 | | - } |
778 | | - private status(principal: HostedPrincipal | null, csrf: string | null): HostedAuthStatus { |
779 | | - return Object.freeze({ |
| 757 | + private status(principal: HostedPrincipal | null, csrfToken: string | null) { |
| 758 | + return projectHostedAuthStatus({ |
780 | 759 | mode: this.dependencies.mode, |
781 | | - authenticated: principal !== null, |
782 | 760 | principal, |
783 | | - csrfToken: csrf, |
| 761 | + csrfToken, |
784 | 762 | oidcProviderName: |
785 | 763 | this.dependencies.oidc === null ? null : this.dependencies.authentication.displayName, |
786 | | - deploymentId: (principal && this.dependencies.runtimeIdentity?.deploymentId) ?? null, |
787 | | - bootId: (principal && this.dependencies.runtimeIdentity?.bootId) ?? null, |
| 764 | + runtimeIdentity: this.dependencies.runtimeIdentity, |
788 | 765 | }); |
789 | 766 | } |
790 | 767 | private admitOidcLogin(source: string): boolean { |
|
0 commit comments