Skip to content

Commit 99cd0c5

Browse files
sahitya-chandraDevanshusharma2005kart1kaRyukemeisteranikdhabal
authored
fix: Use Memberships with OWNER role for platform owner lookup (calcom#22475)
* fix platform owner identification to use Memberships with OWNER role * replaced the hardcoded OWNER string with the enum value * replaced enum with hard coded OWNER value for safty * added enum usage * added admin lookout if owner validation fails * chore * chore * fixed tests * chore * chore * chore * chore --------- Co-authored-by: Devanshu Sharma <devanshusharma658@gmail.com> Co-authored-by: Kartik Saini <41051387+kart1ka@users.noreply.github.com> Co-authored-by: Rajiv Sahal <sahalrajiv-extc@atharvacoe.ac.in> Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
1 parent 2266301 commit 99cd0c5

6 files changed

Lines changed: 75 additions & 6 deletions

File tree

apps/api/v2/src/app.e2e-spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { TestingModule } from "@nestjs/testing";
99
import { Test } from "@nestjs/testing";
1010
import * as request from "supertest";
1111
import { ApiKeysRepositoryFixture } from "test/fixtures/repository/api-keys.repository.fixture";
12+
import { MembershipRepositoryFixture } from "test/fixtures/repository/membership.repository.fixture";
1213
import { OAuthClientRepositoryFixture } from "test/fixtures/repository/oauth-client.repository.fixture";
1314
import { OrganizationRepositoryFixture } from "test/fixtures/repository/organization.repository.fixture";
1415
import { ProfileRepositoryFixture } from "test/fixtures/repository/profiles.repository.fixture";
@@ -33,6 +34,7 @@ describe("AppController", () => {
3334
let organizationsRepositoryFixture: OrganizationRepositoryFixture;
3435
let oauthClientRepositoryFixture: OAuthClientRepositoryFixture;
3536
let profilesRepositoryFixture: ProfileRepositoryFixture;
37+
let membershipRepositoryFixture: MembershipRepositoryFixture;
3638

3739
let apiKeyString: string;
3840

@@ -108,6 +110,14 @@ describe("AppController", () => {
108110
organization: { connect: { id: organization.id } },
109111
});
110112

113+
membershipRepositoryFixture = new MembershipRepositoryFixture(moduleRef);
114+
await membershipRepositoryFixture.create({
115+
user: { connect: { id: user.id } },
116+
team: { connect: { id: organization.id } },
117+
role: "OWNER",
118+
accepted: true,
119+
});
120+
111121
app = moduleRef.createNestApplication();
112122
await app.init();
113123
});

apps/api/v2/src/modules/auth/auth.module.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { NextAuthStrategy } from "@/modules/auth/strategies/next-auth/next-auth.
66
import { DeploymentsModule } from "@/modules/deployments/deployments.module";
77
import { MembershipsModule } from "@/modules/memberships/memberships.module";
88
import { OAuthFlowService } from "@/modules/oauth-clients/services/oauth-flow.service";
9-
import { ProfilesModule } from "@/modules/profiles/profiles.module";
109
import { RedisModule } from "@/modules/redis/redis.module";
1110
import { TokensModule } from "@/modules/tokens/tokens.module";
1211
import { UsersModule } from "@/modules/users/users.module";
@@ -22,7 +21,6 @@ import { PassportModule } from "@nestjs/passport";
2221
MembershipsModule,
2322
TokensModule,
2423
DeploymentsModule,
25-
ProfilesModule,
2624
],
2725
providers: [NextAuthGuard, NextAuthStrategy, ApiAuthGuard, ApiAuthStrategy, OAuthFlowService],
2826
exports: [NextAuthGuard, ApiAuthGuard],

apps/api/v2/src/modules/auth/strategies/api-auth/api-auth.strategy.e2e-spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { ApiKeysRepository } from "@/modules/api-keys/api-keys-repository";
44
import { DeploymentsRepository } from "@/modules/deployments/deployments.repository";
55
import { DeploymentsService } from "@/modules/deployments/deployments.service";
66
import { JwtService } from "@/modules/jwt/jwt.service";
7+
import { MembershipsModule } from "@/modules/memberships/memberships.module";
78
import { OAuthClientRepository } from "@/modules/oauth-clients/oauth-client.repository";
89
import { OAuthFlowService } from "@/modules/oauth-clients/services/oauth-flow.service";
910
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
@@ -20,6 +21,7 @@ import { Test, TestingModule } from "@nestjs/testing";
2021
import { PlatformOAuthClient, Team, User } from "@prisma/client";
2122
import { createRequest } from "node-mocks-http";
2223
import { ApiKeysRepositoryFixture } from "test/fixtures/repository/api-keys.repository.fixture";
24+
import { MembershipRepositoryFixture } from "test/fixtures/repository/membership.repository.fixture";
2325
import { OAuthClientRepositoryFixture } from "test/fixtures/repository/oauth-client.repository.fixture";
2426
import { ProfileRepositoryFixture } from "test/fixtures/repository/profiles.repository.fixture";
2527
import { TeamRepositoryFixture } from "test/fixtures/repository/team.repository.fixture";
@@ -45,6 +47,7 @@ describe("ApiAuthStrategy", () => {
4547
let apiKeysRepositoryFixture: ApiKeysRepositoryFixture;
4648
let oAuthClientRepositoryFixture: OAuthClientRepositoryFixture;
4749
let profilesRepositoryFixture: ProfileRepositoryFixture;
50+
let membershipRepositoryFixture: MembershipRepositoryFixture;
4851

4952
const validApiKeyEmail = `api-auth-api-key-user-${randomString()}@api.com`;
5053
const validAccessTokenEmail = `api-auth-access-token-user-${randomString()}@api.com`;
@@ -65,6 +68,7 @@ describe("ApiAuthStrategy", () => {
6568
}),
6669
ProfilesModule,
6770
TokensModule,
71+
MembershipsModule,
6872
],
6973
providers: [
7074
MockedRedisService,
@@ -91,6 +95,7 @@ describe("ApiAuthStrategy", () => {
9195
teamRepositoryFixture = new TeamRepositoryFixture(module);
9296
oAuthClientRepositoryFixture = new OAuthClientRepositoryFixture(module);
9397
profilesRepositoryFixture = new ProfileRepositoryFixture(module);
98+
membershipRepositoryFixture = new MembershipRepositoryFixture(module);
9499
organization = await teamRepositoryFixture.create({ name: `api-auth-organization-1-${randomString()}` });
95100
organizationTwo = await teamRepositoryFixture.create({
96101
name: `api-auth-organization-2-${randomString()}`,
@@ -121,6 +126,20 @@ describe("ApiAuthStrategy", () => {
121126
organization: { connect: { id: organizationTwo.id } },
122127
});
123128

129+
await membershipRepositoryFixture.create({
130+
user: { connect: { id: validOAuthUser.id } },
131+
team: { connect: { id: organization.id } },
132+
role: "OWNER",
133+
accepted: true,
134+
});
135+
136+
await membershipRepositoryFixture.create({
137+
user: { connect: { id: validOAuthUser.id } },
138+
team: { connect: { id: organizationTwo.id } },
139+
role: "OWNER",
140+
accepted: true,
141+
});
142+
124143
const data = {
125144
logo: "logo-url",
126145
name: "name",

apps/api/v2/src/modules/auth/strategies/api-auth/api-auth.strategy.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import { isOriginAllowed } from "@/lib/is-origin-allowed/is-origin-allowed";
44
import { BaseStrategy } from "@/lib/passport/strategies/types";
55
import { ApiKeysRepository } from "@/modules/api-keys/api-keys-repository";
66
import { DeploymentsService } from "@/modules/deployments/deployments.service";
7+
import { MembershipsRepository } from "@/modules/memberships/memberships.repository";
78
import { OAuthClientRepository } from "@/modules/oauth-clients/oauth-client.repository";
89
import { OAuthFlowService } from "@/modules/oauth-clients/services/oauth-flow.service";
9-
import { ProfilesRepository } from "@/modules/profiles/profiles.repository";
1010
import { TokensRepository } from "@/modules/tokens/tokens.repository";
1111
import { TokensService } from "@/modules/tokens/tokens.service";
1212
import { UsersService } from "@/modules/users/services/users.service";
@@ -45,8 +45,8 @@ export class ApiAuthStrategy extends PassportStrategy(BaseStrategy, "api-auth")
4545
private readonly userRepository: UsersRepository,
4646
private readonly apiKeyRepository: ApiKeysRepository,
4747
private readonly oauthRepository: OAuthClientRepository,
48-
private readonly profilesRepository: ProfilesRepository,
49-
private readonly usersService: UsersService
48+
private readonly usersService: UsersService,
49+
private readonly membershipsRepository: MembershipsRepository
5050
) {
5151
super();
5252
}
@@ -172,7 +172,9 @@ export class ApiAuthStrategy extends PassportStrategy(BaseStrategy, "api-auth")
172172
throw new UnauthorizedException("ApiAuthStrategy - oAuth client - Invalid client secret");
173173
}
174174

175-
const platformCreatorId = await this.profilesRepository.getPlatformOwnerUserId(client.organizationId);
175+
const platformCreatorId =
176+
(await this.membershipsRepository.findPlatformOwnerUserId(client.organizationId)) ||
177+
(await this.membershipsRepository.findPlatformAdminUserId(client.organizationId));
176178

177179
if (!platformCreatorId) {
178180
throw new UnauthorizedException(

apps/api/v2/src/modules/memberships/memberships.repository.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,36 @@ export class MembershipsRepository {
2020
return membership;
2121
}
2222

23+
async findPlatformOwnerUserId(organizationId: number): Promise<number | undefined> {
24+
const owner = await this.dbRead.prisma.membership.findFirst({
25+
where: {
26+
teamId: organizationId,
27+
role: "OWNER",
28+
accepted: true,
29+
},
30+
select: {
31+
userId: true,
32+
},
33+
});
34+
35+
return owner?.userId ?? undefined;
36+
}
37+
38+
async findPlatformAdminUserId(organizationId: number): Promise<number | undefined> {
39+
const admin = await this.dbRead.prisma.membership.findFirst({
40+
where: {
41+
teamId: organizationId,
42+
role: "ADMIN",
43+
accepted: true,
44+
},
45+
select: {
46+
userId: true,
47+
},
48+
});
49+
50+
return admin?.userId ?? undefined;
51+
}
52+
2353
async findMembershipByTeamId(teamId: number, userId: number) {
2454
const membership = await this.dbRead.prisma.membership.findUnique({
2555
where: {

apps/api/v2/src/modules/oauth-clients/controllers/oauth-flow/oauth-flow.controller.e2e-spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { NestExpressApplication } from "@nestjs/platform-express";
1515
import { Test, TestingModule } from "@nestjs/testing";
1616
import { PlatformOAuthClient, Team, User } from "@prisma/client";
1717
import * as request from "supertest";
18+
import { MembershipRepositoryFixture } from "test/fixtures/repository/membership.repository.fixture";
1819
import { OAuthClientRepositoryFixture } from "test/fixtures/repository/oauth-client.repository.fixture";
1920
import { OrganizationRepositoryFixture } from "test/fixtures/repository/organization.repository.fixture";
2021
import { ProfileRepositoryFixture } from "test/fixtures/repository/profiles.repository.fixture";
@@ -63,6 +64,7 @@ describe("OAuthFlow Endpoints", () => {
6364
let organizationsRepositoryFixture: OrganizationRepositoryFixture;
6465
let oAuthClientsRepositoryFixture: OAuthClientRepositoryFixture;
6566
let profilesRepositoryFixture: ProfileRepositoryFixture;
67+
let membershipRepositoryFixture: MembershipRepositoryFixture;
6668

6769
let user: User;
6870
let organization: Team;
@@ -89,6 +91,7 @@ describe("OAuthFlow Endpoints", () => {
8991
organizationsRepositoryFixture = new OrganizationRepositoryFixture(moduleRef);
9092
usersRepositoryFixtures = new UserRepositoryFixture(moduleRef);
9193
profilesRepositoryFixture = new ProfileRepositoryFixture(moduleRef);
94+
membershipRepositoryFixture = new MembershipRepositoryFixture(moduleRef);
9295

9396
user = await usersRepositoryFixtures.create({
9497
email: userEmail,
@@ -104,6 +107,13 @@ describe("OAuthFlow Endpoints", () => {
104107
movedFromUser: { connect: { id: user.id } },
105108
organization: { connect: { id: organization.id } },
106109
});
110+
111+
await membershipRepositoryFixture.create({
112+
user: { connect: { id: user.id } },
113+
team: { connect: { id: organization.id } },
114+
role: "OWNER",
115+
accepted: true,
116+
});
107117
oAuthClient = await createOAuthClient(organization.id);
108118
});
109119

0 commit comments

Comments
 (0)