Skip to content

Commit 7f7525b

Browse files
committed
[NEW] Enable LDAP manual sync to deployments without EE license
1 parent f1ce17d commit 7f7525b

File tree

7 files changed

+47
-19
lines changed

7 files changed

+47
-19
lines changed

app/api/server/api.d.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import type { JoinPathPattern, Method, MethodOf, OperationParams, OperationResult, PathPattern, UrlParams } from '../../../definition/rest';
22
import type { IUser } from '../../../definition/IUser';
3+
import { IMethodConnection } from '../../../definition/IMethodThisType';
4+
import { ITwoFactorOptions } from '../../2fa/server/code';
35

46
type SuccessResult<T> = {
57
statusCode: 200;
@@ -41,9 +43,17 @@ type UnauthorizedResult<T> = {
4143

4244
type Options = {
4345
permissionsRequired?: string[];
44-
twoFactorOptions?: unknown;
46+
twoFactorOptions?: ITwoFactorOptions;
4547
twoFactorRequired?: boolean;
4648
authRequired?: boolean;
49+
enterprise?: boolean;
50+
}
51+
52+
type Request = {
53+
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
54+
url: string;
55+
headers: Record<string, string>;
56+
body: any;
4757
}
4858

4959
type ActionThis<TMethod extends Method, TPathPattern extends PathPattern, TOptions> = {
@@ -93,6 +103,8 @@ type Operations<TPathPattern extends PathPattern, TOptions extends Options = {}>
93103
};
94104

95105
declare class APIClass<TBasePath extends string = '/'> {
106+
processTwoFactor({ userId, request, invocation, options, connection }: { userId: string; request: Request; invocation: {twoFactorChecked: boolean}; options: Options; connection: IMethodConnection }): void;
107+
96108
addRoute<
97109
TSubPathPattern extends string
98110
>(subpath: TSubPathPattern, operations: Operations<JoinPathPattern<TBasePath, TSubPathPattern>>): void;

app/api/server/api.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ export class APIClass extends Restivus {
276276
const code = request.headers['x-2fa-code'];
277277
const method = request.headers['x-2fa-method'];
278278

279-
checkCodeForUser({ user: userId, code, method, options, connection });
279+
checkCodeForUser({ user: userId, code, method, options: options.twoFactorOptions, connection });
280280

281281
invocation.twoFactorChecked = true;
282282
}
@@ -400,7 +400,7 @@ export class APIClass extends Restivus {
400400
Accounts._setAccountData(connection.id, 'loginToken', this.token);
401401

402402
if (_options.twoFactorRequired) {
403-
api.processTwoFactor({ userId: this.userId, request: this.request, invocation, options: _options.twoFactorOptions, connection });
403+
api.processTwoFactor({ userId: this.userId, request: this.request, invocation, options: _options, connection });
404404
}
405405

406406
result = DDP._CurrentInvocation.withValue(invocation, () => Promise.await(originalAction.apply(this))) || API.v1.success();

client/lib/2fa/utils.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import { Meteor } from 'meteor/meteor';
44
export const isTotpRequiredError = (
55
error: unknown,
66
): error is Meteor.Error & { error: 'totp-required' } =>
7-
(error as { error?: unknown } | undefined)?.error === 'totp-required';
7+
(error as { error?: unknown } | undefined)?.error === 'totp-required' ||
8+
(error as { errorType?: unknown } | undefined)?.errorType === 'totp-required';
89

910
export const isTotpInvalidError = (
1011
error: unknown,
1112
): error is Meteor.Error & { error: 'totp-invalid' } =>
12-
(error as { error?: unknown } | undefined)?.error === 'totp-invalid';
13+
(error as { error?: unknown } | undefined)?.error === 'totp-invalid' ||
14+
(error as { errorType?: unknown } | undefined)?.errorType === 'totp-invalid';
1315

1416
export const isLoginCancelledError = (error: unknown): error is Meteor.Error =>
1517
error instanceof Meteor.Error && error.error === Accounts.LoginCancelledError.numericError;

client/views/admin/settings/groups/LDAPGroupPage.tsx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ function LDAPGroupPage({ _id, ...group }: ISetting): JSX.Element {
1919
const syncNow = useEndpoint('POST', 'ldap.syncNow');
2020
const testSearch = useEndpoint('POST', 'ldap.testSearch');
2121
const ldapEnabled = useSetting('LDAP_Enable');
22-
const ldapSyncEnabled = useSetting('LDAP_Background_Sync') && ldapEnabled;
2322
const setModal = useSetModal();
2423
const closeModal = useMutableCallback(() => setModal());
2524

@@ -135,13 +134,11 @@ function LDAPGroupPage({ _id, ...group }: ISetting): JSX.Element {
135134
disabled={!ldapEnabled || changed}
136135
onClick={handleSearchTestButtonClick}
137136
/>
138-
{ldapSyncEnabled && (
139-
<Button
140-
children={t('LDAP_Sync_Now')}
141-
disabled={!ldapSyncEnabled || changed}
142-
onClick={handleSyncNowButtonClick}
143-
/>
144-
)}
137+
<Button
138+
children={t('LDAP_Sync_Now')}
139+
disabled={!ldapEnabled || changed}
140+
onClick={handleSyncNowButtonClick}
141+
/>
145142
<Button is='a' href='https://go.rocket.chat/i/ldap-docs' target='_blank'>
146143
{t('LDAP_Documentation')}
147144
</Button>

ee/server/api/api.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { API } from '../../../app/api/server/api';
2+
import { use } from '../../../app/settings/server/Middleware';
3+
import { isEnterprise } from '../../app/license/server/license';
4+
5+
// Overwrites two factor method to enforce 2FA check for enterprise APIs when
6+
// no license was provided to prevent abuse on enterprise APIs.
7+
API.v1.processTwoFactor = use(API.v1.processTwoFactor, function(context, next) {
8+
const [params] = context;
9+
10+
if (params.options?.enterprise && params.options?.twoFactorRequired && !params.options.twoFactorOptions?.requireSecondFactor) {
11+
params.options = {
12+
...params.options,
13+
twoFactorOptions: {
14+
...params.options.twoFactorOptions,
15+
requireSecondFactor: !isEnterprise(),
16+
},
17+
};
18+
}
19+
20+
return next(params);
21+
});

ee/server/api/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
import './api';
12
import './ldap';
23
import './licenses';

ee/server/api/ldap.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@ import { hasRole } from '../../../app/authorization/server';
22
import { settings } from '../../../app/settings/server';
33
import { API } from '../../../app/api/server/api';
44
import { LDAPEE } from '../sdk';
5-
import { hasLicense } from '../../app/license/server/license';
65

7-
API.v1.addRoute('ldap.syncNow', { authRequired: true }, {
6+
API.v1.addRoute('ldap.syncNow', { authRequired: true, enterprise: true, twoFactorRequired: true }, {
87
async post() {
98
if (!this.userId) {
109
throw new Error('error-invalid-user');
@@ -14,10 +13,6 @@ API.v1.addRoute('ldap.syncNow', { authRequired: true }, {
1413
throw new Error('error-not-authorized');
1514
}
1615

17-
if (!hasLicense('ldap-enterprise')) {
18-
throw new Error('error-not-authorized');
19-
}
20-
2116
if (settings.get('LDAP_Enable') !== true) {
2217
throw new Error('LDAP_disabled');
2318
}

0 commit comments

Comments
 (0)