Skip to content

Commit decf62e

Browse files
committed
Stop scoping Session.roles
1 parent 48a0263 commit decf62e

File tree

14 files changed

+30
-86
lines changed

14 files changed

+30
-86
lines changed

src/components/authorization/dto/role.dto.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
import { type Role } from '~/common';
22

3-
export type ProjectScope = 'project';
4-
export type GlobalScope = 'global';
5-
6-
// Scope for roles. Does this role apply anywhere or only with project membership?
7-
export type AuthScope = GlobalScope | ProjectScope;
8-
9-
export type ProjectScopedRole = `${ProjectScope}:${Role}`;
10-
export type GlobalScopedRole = `${GlobalScope}:${Role}`;
3+
type AuthScope = 'global' | 'project';
114

125
export type ScopedRole = `${AuthScope}:${Role}` | 'member:true';
136

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { CanImpersonateEvent } from '~/core/authentication/events/can-impersonate.event';
22
import { EventsHandler } from '~/core/events';
3-
import { withoutScope } from '../dto';
43
import { AssignableRoles } from '../dto/assignable-roles.dto';
54
import { Privileges } from '../policy';
65

@@ -10,9 +9,7 @@ export class CanImpersonateHandler {
109

1110
handle(event: CanImpersonateEvent) {
1211
const p = this.privileges.for(AssignableRoles);
13-
const valid = event.session.roles.every((role) =>
14-
p.can('edit', withoutScope(role)),
15-
);
12+
const valid = event.session.roles.every((role) => p.can('edit', role));
1613
event.allow.vote(valid);
1714
}
1815
}

src/components/authorization/policies/conditions/role.condition.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { inspect } from 'util';
22
import { type Role } from '~/common';
3-
import { withoutScope } from '../../dto';
43
import {
54
type AsEdgeQLParams,
65
type Condition,
@@ -13,7 +12,7 @@ export class RoleCondition implements Condition {
1312
constructor(readonly allowed: ReadonlySet<Role>) {}
1413

1514
isAllowed({ session }: IsAllowedParams<any>) {
16-
const given = session.roles.map(withoutScope);
15+
const given = session.roles;
1716
return given.some((role) => this.allowed.has(role));
1817
}
1918

src/components/authorization/policy/executor/policy-executor.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { identity, intersection } from 'lodash';
44
import { type EnhancedResource } from '~/common';
55
import { Identity, type Session } from '~/core/authentication';
66
import { type QueryFragment } from '~/core/database/query';
7-
import { withoutScope } from '../../dto';
87
import { RoleCondition } from '../../policies/conditions/role.condition';
98
import { type Permission } from '../builder/perm-granter';
109
import {
@@ -282,7 +281,7 @@ export class PolicyExecutor {
282281
}
283282
const rolesSpecifiedByPolicyThatUserHas = intersection(
284283
policy.roles,
285-
session.roles.map(withoutScope),
284+
session.roles,
286285
);
287286
return rolesSpecifiedByPolicyThatUserHas.length > 0;
288287
});

src/components/engagement/engagement.rules.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { ILogger, Logger } from '~/core';
1212
import { Identity } from '~/core/authentication';
1313
import { DatabaseService } from '~/core/database';
1414
import { ACTIVE, INACTIVE } from '~/core/database/query';
15-
import { withoutScope } from '../authorization/dto';
1615
import { ProjectStep } from '../project/dto';
1716
import {
1817
EngagementStatus,
@@ -314,7 +313,7 @@ export class EngagementRules {
314313

315314
async getAvailableTransitions(
316315
engagementId: ID,
317-
currentUserRoles?: Role[],
316+
currentUserRoles?: readonly Role[],
318317
changeset?: ID,
319318
): Promise<EngagementStatusTransition[]> {
320319
const session = this.identity.current;
@@ -330,7 +329,7 @@ export class EngagementRules {
330329
);
331330

332331
// If current user is not an approver (based on roles) then don't allow any transitions
333-
currentUserRoles ??= session.roles.map(withoutScope);
332+
currentUserRoles ??= session.roles;
334333
if (intersection(approvers, currentUserRoles).length === 0) {
335334
return [];
336335
}
@@ -358,7 +357,7 @@ export class EngagementRules {
358357

359358
async canBypassWorkflow() {
360359
const session = this.identity.current;
361-
const roles = session.roles.map(withoutScope);
360+
const roles = session.roles;
362361
return intersection(rolesThatCanBypassWorkflow, roles).length > 0;
363362
}
364363

@@ -370,7 +369,7 @@ export class EngagementRules {
370369
// If current user's roles include a role that can bypass workflow
371370
// stop the check here.
372371
const session = this.identity.current;
373-
const currentUserRoles = session.roles.map(withoutScope);
372+
const currentUserRoles = session.roles;
374373
if (intersection(rolesThatCanBypassWorkflow, currentUserRoles).length > 0) {
375374
return;
376375
}

src/components/project/project.service.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import { Identity } from '~/core/authentication';
2525
import { Transactional } from '~/core/database';
2626
import { type AnyChangesOf } from '~/core/database/changes';
2727
import { Privileges } from '../authorization';
28-
import { withoutScope } from '../authorization/dto';
2928
import { BudgetService } from '../budget';
3029
import { BudgetStatus, type SecuredBudget } from '../budget/dto';
3130
import { EngagementService } from '../engagement';
@@ -160,9 +159,9 @@ export class ProjectService {
160159
await this.projectMembers.create(
161160
{
162161
userId: session.userId,
163-
roles: session.roles
164-
.map(withoutScope)
165-
.filter((role) => Role.applicableToProjectMembership.has(role)),
162+
roles: session.roles.filter((role) =>
163+
Role.applicableToProjectMembership.has(role),
164+
),
166165
projectId: project,
167166
},
168167
false,

src/core/authentication/authentication.gel.repository.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
22
import { IntegrityError } from 'gel';
33
import { type ID, type PublicOf, ServerException } from '~/common';
44
import { RootUserAlias } from '../config/root-user.config';
5-
import { DbTraceLayer, disableAccessPolicies, e, Gel, withScope } from '../gel';
5+
import { DbTraceLayer, disableAccessPolicies, e, Gel } from '../gel';
66
import type { AuthenticationRepository } from './authentication.repository';
77
import { type LoginInput } from './dto';
88
import { type Session } from './session/session.dto';
@@ -138,8 +138,8 @@ export class AuthenticationGelRepository
138138
return e.select(e.Auth.Session, (session) => ({
139139
filter_single: { token },
140140
userId: session.user.id,
141-
roles: withScope('global', session.user.roles),
142-
impersonateeRoles: withScope('global', impersonatee.roles),
141+
roles: session.user.roles,
142+
impersonateeRoles: impersonatee.roles,
143143
}));
144144
},
145145
);
@@ -151,7 +151,7 @@ export class AuthenticationGelRepository
151151
{ userId: e.uuid },
152152
({ userId }) => {
153153
const user = e.cast(e.User, userId);
154-
return withScope('global', user.roles);
154+
return user.roles;
155155
},
156156
);
157157

src/core/authentication/authentication.repository.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { Injectable } from '@nestjs/common';
22
import { node, relation } from 'cypher-query-builder';
33
import { DateTime } from 'luxon';
4-
import { type ID, ServerException } from '~/common';
5-
import { type ScopedRole } from '../../components/authorization/dto';
4+
import { type ID, type Role, ServerException } from '~/common';
65
import { DatabaseService, DbTraceLayer, OnIndex } from '../database';
76
import {
87
ACTIVE,
@@ -201,8 +200,8 @@ export class AuthenticationRepository {
201200
)
202201
.return<{
203202
userId: ID | null;
204-
roles: readonly ScopedRole[];
205-
impersonateeRoles: readonly ScopedRole[] | null;
203+
roles: readonly Role[];
204+
impersonateeRoles: readonly Role[] | null;
206205
}>([
207206
'user.id as userId',
208207
'roles',

src/core/authentication/session/session.dto.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import { type DateTime } from 'luxon';
2-
import { DataObject, UnauthenticatedException } from '~/common';
2+
import { DataObject, type Role, UnauthenticatedException } from '~/common';
33
import { type ID } from '~/common/id-field';
4-
import { type ScopedRole } from '../../../components/authorization/dto';
54

65
class RawSession extends DataObject {
76
readonly token: string;
87
readonly issuedAt: DateTime;
98
readonly userId: ID;
10-
readonly roles: readonly ScopedRole[];
9+
readonly roles: readonly Role[];
1110
readonly anonymous: boolean;
1211

1312
/**
@@ -19,7 +18,7 @@ class RawSession extends DataObject {
1918
*/
2019
readonly impersonatee?: {
2120
id?: ID;
22-
roles: readonly ScopedRole[];
21+
roles: readonly Role[];
2322
};
2423
}
2524

@@ -42,7 +41,7 @@ export class Session extends RawSession {
4241
}
4342

4443
get isAdmin() {
45-
return this.roles.includes('global:Administrator');
44+
return this.roles.includes('Administrator');
4645
}
4746

4847
isSelf(id: ID<'User'>) {

src/core/authentication/session/session.initiator.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
} from '~/common';
1212
import { ConfigService } from '~/core/config/config.service';
1313
import { ILogger, Logger } from '~/core/logger';
14-
import { rolesForScope } from '../../../components/authorization/dto';
1514
import { type IRequest } from '../../http';
1615
import { type Session } from './session.dto';
1716
import { type SessionManager } from './session.manager';
@@ -97,9 +96,7 @@ export class SessionInitiator {
9796
return undefined;
9897
}
9998

100-
const scoped = (roles ?? [])
101-
.map(assertValidRole)
102-
.map(rolesForScope('global'));
99+
const scoped = (roles ?? []).map(assertValidRole);
103100

104101
return { id: user, roles: scoped };
105102
}

0 commit comments

Comments
 (0)