Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

N21-1505 Prevent deletion of global systems #4574

Merged
merged 9 commits into from
Nov 24, 2023
19 changes: 11 additions & 8 deletions apps/server/src/apps/server.app.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,34 @@
/* istanbul ignore file */
import { Mail, MailService } from '@infra/mail';
// application imports
/* eslint-disable no-console */
import { MikroORM } from '@mikro-orm/core';
import { NestFactory } from '@nestjs/core';
import { ExpressAdapter } from '@nestjs/platform-express';
import { enableOpenApiDocs } from '@shared/controller/swagger';
import { Mail, MailService } from '@infra/mail';
import { LegacyLogger, Logger } from '@src/core/logger';
import { AccountService } from '@modules/account';
import { TeamService } from '@modules/teams/service/team.service';
import { AccountValidationService } from '@modules/account/services/account.validation.service';

Check warning on line 7 in apps/server/src/apps/server.app.ts

View workflow job for this annotation

GitHub Actions / nest_lint

'@modules/account/services/account.validation.service' import is restricted from being used by a pattern. Do not deep import from a module
import { AccountUc } from '@modules/account/uc/account.uc';

Check warning on line 8 in apps/server/src/apps/server.app.ts

View workflow job for this annotation

GitHub Actions / nest_lint

'@modules/account/uc/account.uc' import is restricted from being used by a pattern. Do not deep import from a module
import { SystemRule } from '@modules/authorization/domain/rules';

Check warning on line 9 in apps/server/src/apps/server.app.ts

View workflow job for this annotation

GitHub Actions / nest_lint

'@modules/authorization/domain/rules' import is restricted from being used by a pattern. Do not deep import from a module
import { CollaborativeStorageUc } from '@modules/collaborative-storage/uc/collaborative-storage.uc';

Check warning on line 10 in apps/server/src/apps/server.app.ts

View workflow job for this annotation

GitHub Actions / nest_lint

'@modules/collaborative-storage/uc/collaborative-storage.uc' import is restricted from being used by a pattern. Do not deep import from a module
import { GroupService } from '@modules/group';
import { FeathersRosterService } from '@modules/pseudonym';
import { RocketChatService } from '@modules/rocketchat';
import { ServerModule } from '@modules/server';
import { TeamService } from '@modules/teams/service/team.service';

Check warning on line 15 in apps/server/src/apps/server.app.ts

View workflow job for this annotation

GitHub Actions / nest_lint

'@modules/teams/service/team.service' import is restricted from being used by a pattern. Do not deep import from a module
import { NestFactory } from '@nestjs/core';
import { ExpressAdapter } from '@nestjs/platform-express';
import { enableOpenApiDocs } from '@shared/controller/swagger';
import { LegacyLogger, Logger } from '@src/core/logger';
import express from 'express';
import { join } from 'path';

// register source-map-support for debugging
import { install as sourceMapInstall } from 'source-map-support';
import { FeathersRosterService } from '@modules/pseudonym';
import legacyAppPromise = require('../../../../src/app');

import { AppStartLoggable } from './helpers/app-start-loggable';
import {
addPrometheusMetricsMiddlewaresIfEnabled,
createAndStartPrometheusMetricsAppIfEnabled,
} from './helpers/prometheus-metrics';
import legacyAppPromise = require('../../../../src/app');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dont know if you really want to push those import order changes


async function bootstrap() {
sourceMapInstall();
Expand Down Expand Up @@ -85,6 +86,8 @@
feathersExpress.services['nest-feathers-roster-service'] = nestApp.get(FeathersRosterService);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access
feathersExpress.services['nest-group-service'] = nestApp.get(GroupService);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access
feathersExpress.services['nest-system-rule'] = nestApp.get(SystemRule);
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment
feathersExpress.services['nest-orm'] = orm;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { createMock } from '@golevelup/ts-jest';
import { MongoMemoryDatabaseModule } from '@infra/database';
import KeycloakAdminClient from '@keycloak/keycloak-admin-client-cjs/keycloak-admin-client-cjs-index';
import AuthenticationExecutionExportRepresentation from '@keycloak/keycloak-admin-client/lib/defs/authenticationExecutionExportRepresentation';
import AuthenticationFlowRepresentation from '@keycloak/keycloak-admin-client/lib/defs/authenticationFlowRepresentation';
import { LegacySystemService } from '@modules/system';
import { ConfigModule } from '@nestjs/config';
import { Test, TestingModule } from '@nestjs/testing';
import { MongoMemoryDatabaseModule } from '@infra/database';
import { SystemRepo } from '@shared/repo/system/system.repo';
import { systemFactory } from '@shared/testing/factory';
import { LegacySystemRepo } from '@shared/repo';
import { systemEntityFactory } from '@shared/testing/factory';
import { LoggerModule } from '@src/core/logger';
import { SystemService } from '@modules/system/service/system.service';
import { v1 } from 'uuid';
import { KeycloakAdministrationService } from '../../keycloak-administration/service/keycloak-administration.service';
import { KeycloakConfigurationModule } from '../keycloak-configuration.module';
Expand All @@ -17,15 +17,15 @@ import { KeycloakConfigurationService } from './keycloak-configuration.service';
describe('KeycloakConfigurationService Integration', () => {
let module: TestingModule;
let keycloak: KeycloakAdminClient;
let systemRepo: SystemRepo;
let systemRepo: LegacySystemRepo;
let keycloakAdministrationService: KeycloakAdministrationService;
let keycloakConfigurationService: KeycloakConfigurationService;
let isKeycloakAvailable = false;

const testRealm = `test-realm-${v1().toString()}`;
const flowAlias = 'Direct Broker Flow';
const systemServiceMock = createMock<SystemService>();
const systems = systemFactory.withOidcConfig().buildList(1);
const systemServiceMock = createMock<LegacySystemService>();
const systems = systemEntityFactory.withOidcConfig().buildList(1);

beforeAll(async () => {
module = await Test.createTestingModule({
Expand All @@ -38,9 +38,9 @@ describe('KeycloakConfigurationService Integration', () => {
validationOptions: { infer: true },
}),
],
providers: [SystemRepo],
providers: [LegacySystemRepo],
}).compile();
systemRepo = module.get(SystemRepo);
systemRepo = module.get(LegacySystemRepo);
keycloakAdministrationService = module.get(KeycloakAdministrationService);
keycloakConfigurationService = module.get(KeycloakConfigurationService);
isKeycloakAvailable = await keycloakAdministrationService.testKcConnection();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { HttpService } from '@nestjs/axios';
import { ConfigService } from '@nestjs/config';
import { Test, TestingModule } from '@nestjs/testing';
import { SystemEntity, SystemTypeEnum } from '@shared/domain';
import { systemFactory } from '@shared/testing';
import { systemEntityFactory } from '@shared/testing';
import { AxiosResponse } from 'axios';
import { of } from 'rxjs';
import { v1 } from 'uuid';
Expand Down Expand Up @@ -63,7 +63,9 @@ describe('KeycloakConfigurationService Unit', () => {
};
};

const systems: SystemEntity[] = systemFactory.withOidcConfig().buildListWithId(1, { type: SystemTypeEnum.OIDC });
const systems: SystemEntity[] = systemEntityFactory
.withOidcConfig()
.buildListWithId(1, { type: SystemTypeEnum.OIDC });
const oidcSystems = SystemOidcMapper.mapFromEntitiesToDtos(systems);
const idps: IdentityProviderRepresentation[] = [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DefaultEncryptionService, EncryptionService } from '@infra/encryption';
import { OauthConfigDto } from '@modules/system/service';
import { OauthConfigDto } from '@modules/system/service/dto';
import { HttpService } from '@nestjs/axios';
import { Inject, Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
Expand Down
4 changes: 2 additions & 2 deletions apps/server/src/modules/account/account.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { IdentityManagementModule } from '@infra/identity-management';
import { Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PermissionService } from '@shared/domain';
import { SystemRepo, UserRepo } from '@shared/repo';
import { LegacySystemRepo, UserRepo } from '@shared/repo';
import { LoggerModule } from '@src/core/logger/logger.module';
import { ServerConfig } from '../server/server.config';
import { AccountIdmToDtoMapper, AccountIdmToDtoMapperDb, AccountIdmToDtoMapperIdm } from './mapper';
Expand All @@ -24,7 +24,7 @@ function accountIdmToDtoMapperFactory(configService: ConfigService<ServerConfig,
imports: [IdentityManagementModule, LoggerModule],
providers: [
UserRepo,
SystemRepo,
LegacySystemRepo,
PermissionService,
AccountRepo,
AccountServiceDb,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Test, TestingModule } from '@nestjs/testing';
import { EntityNotFoundError } from '@shared/common';
import { Account, EntityId, Permission, Role, RoleName, User } from '@shared/domain';
import { UserRepo } from '@shared/repo';
import { accountFactory, setupEntities, systemFactory, userFactory } from '@shared/testing';
import { accountFactory, setupEntities, systemEntityFactory, userFactory } from '@shared/testing';
import { ObjectId } from 'bson';
import { AccountRepo } from '../repo/account.repo';
import { AccountValidationService } from './account.validation.service';
Expand Down Expand Up @@ -133,8 +133,8 @@ describe('AccountValidationService', () => {
mockOtherTeacherAccount = accountFactory.buildWithId({
userId: mockOtherTeacherUser.id,
});
const externalSystemA = systemFactory.buildWithId();
const externalSystemB = systemFactory.buildWithId();
const externalSystemA = systemEntityFactory.buildWithId();
const externalSystemB = systemEntityFactory.buildWithId();
mockExternalUserAccount = accountFactory.buildWithId({
userId: mockExternalUser.id,
username: 'unique.within@system',
Expand Down
12 changes: 6 additions & 6 deletions apps/server/src/modules/account/uc/account.uc.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
User,
} from '@shared/domain';
import { UserRepo } from '@shared/repo';
import { accountFactory, schoolFactory, setupEntities, systemFactory, userFactory } from '@shared/testing';
import { accountFactory, schoolFactory, setupEntities, systemEntityFactory, userFactory } from '@shared/testing';
import { BruteForcePrevention } from '@src/imports-from-feathers';
import { ObjectId } from 'bson';
import {
Expand Down Expand Up @@ -431,7 +431,7 @@ describe('AccountUc', () => {
userId: mockUnknownRoleUser.id,
password: defaultPasswordHash,
});
const externalSystem = systemFactory.buildWithId();
const externalSystem = systemEntityFactory.buildWithId();
mockExternalUserAccount = accountFactory.buildWithId({
userId: mockExternalUser.id,
password: defaultPasswordHash,
Expand All @@ -440,25 +440,25 @@ describe('AccountUc', () => {
mockAccountWithoutUser = accountFactory.buildWithId({
userId: undefined,
password: defaultPasswordHash,
systemId: systemFactory.buildWithId().id,
systemId: systemEntityFactory.buildWithId().id,
});
mockAccountWithSystemId = accountFactory.withSystemId(new ObjectId(10)).build();
mockAccountWithLastFailedLogin = accountFactory.buildWithId({
userId: undefined,
password: defaultPasswordHash,
systemId: systemFactory.buildWithId().id,
systemId: systemEntityFactory.buildWithId().id,
lasttriedFailedLogin: new Date(),
});
mockAccountWithOldLastFailedLogin = accountFactory.buildWithId({
userId: undefined,
password: defaultPasswordHash,
systemId: systemFactory.buildWithId().id,
systemId: systemEntityFactory.buildWithId().id,
lasttriedFailedLogin: new Date(new Date().getTime() - LOGIN_BLOCK_TIME - 1),
});
mockAccountWithNoLastFailedLogin = accountFactory.buildWithId({
userId: undefined,
password: defaultPasswordHash,
systemId: systemFactory.buildWithId().id,
systemId: systemEntityFactory.buildWithId().id,
lasttriedFailedLogin: undefined,
});

Expand Down
12 changes: 6 additions & 6 deletions apps/server/src/modules/authentication/authentication.module.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Module } from '@nestjs/common';
import { JwtModule, JwtModuleOptions } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { CacheWrapperModule } from '@infra/cache';
import { IdentityManagementModule } from '@infra/identity-management';
import { LegacySchoolRepo, SystemRepo, UserRepo } from '@shared/repo';
import { LoggerModule } from '@src/core/logger';
import { AccountModule } from '@modules/account';
import { OauthModule } from '@modules/oauth/oauth.module';
import { RoleModule } from '@modules/role';
import { SystemModule } from '@modules/system';
import { Module } from '@nestjs/common';
import { JwtModule, JwtModuleOptions } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { LegacySchoolRepo, LegacySystemRepo, UserRepo } from '@shared/repo';
import { LoggerModule } from '@src/core/logger';
import { Algorithm, SignOptions } from 'jsonwebtoken';
import { jwtConstants } from './constants';
import { AuthenticationService } from './services/authentication.service';
Expand Down Expand Up @@ -69,7 +69,7 @@ const jwtModuleOptions: JwtModuleOptions = {
JwtStrategy,
JwtValidationAdapter,
UserRepo,
SystemRepo,
LegacySystemRepo,
LegacySchoolRepo,
LocalStrategy,
AuthenticationService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ServerTestModule } from '@modules/server/server.module';
import { HttpStatus, INestApplication } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { Account, RoleName, SchoolEntity, SystemEntity, User } from '@shared/domain';
import { accountFactory, roleFactory, schoolFactory, systemFactory, userFactory } from '@shared/testing';
import { accountFactory, roleFactory, schoolFactory, systemEntityFactory, userFactory } from '@shared/testing';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import crypto, { KeyPairKeyObjectResult } from 'crypto';
Expand Down Expand Up @@ -149,7 +149,7 @@ describe('Login Controller (api)', () => {
describe('when user login succeeds', () => {
const setup = async () => {
const schoolExternalId = 'mockSchoolExternalId';
const system: SystemEntity = systemFactory.withLdapConfig().buildWithId({});
const system: SystemEntity = systemEntityFactory.withLdapConfig().buildWithId({});
const school: SchoolEntity = schoolFactory.buildWithId({ systems: [system], externalId: schoolExternalId });
const studentRoles = roleFactory.build({ name: RoleName.STUDENT, permissions: [] });

Expand Down Expand Up @@ -200,7 +200,7 @@ describe('Login Controller (api)', () => {
describe('when user login fails', () => {
const setup = async () => {
const schoolExternalId = 'mockSchoolExternalId';
const system: SystemEntity = systemFactory.withLdapConfig().buildWithId({});
const system: SystemEntity = systemEntityFactory.withLdapConfig().buildWithId({});
const school: SchoolEntity = schoolFactory.buildWithId({ systems: [system], externalId: schoolExternalId });
const studentRoles = roleFactory.build({ name: RoleName.STUDENT, permissions: [] });

Expand Down Expand Up @@ -238,7 +238,7 @@ describe('Login Controller (api)', () => {
describe('when logging in as a user of the Central LDAP of Brandenburg', () => {
const setup = async () => {
const officialSchoolNumber = '01234';
const system: SystemEntity = systemFactory.withLdapConfig().buildWithId({});
const system: SystemEntity = systemEntityFactory.withLdapConfig().buildWithId({});
const school: SchoolEntity = schoolFactory.buildWithId({
systems: [system],
externalId: officialSchoolNumber,
Expand Down Expand Up @@ -301,7 +301,7 @@ describe('Login Controller (api)', () => {
const schoolExternalId = 'schoolExternalId';
const userExternalId = 'userExternalId';

const system = systemFactory.withOauthConfig().buildWithId({});
const system = systemEntityFactory.withOauthConfig().buildWithId({});
const school = schoolFactory.buildWithId({ systems: [system], externalId: schoolExternalId });
const studentRoles = roleFactory.build({ name: RoleName.STUDENT, permissions: [] });
const user = userFactory.buildWithId({ school, roles: [studentRoles], externalId: userExternalId });
Expand Down Expand Up @@ -391,7 +391,7 @@ describe('Login Controller (api)', () => {
const schoolExternalId = 'schoolExternalId';
const userExternalId = 'userExternalId';

const system = systemFactory.withOauthConfig().buildWithId({});
const system = systemEntityFactory.withOauthConfig().buildWithId({});
const school = schoolFactory.buildWithId({ systems: [system], externalId: schoolExternalId });
const studentRoles = roleFactory.build({ name: RoleName.STUDENT, permissions: [] });
const user = userFactory.buildWithId({ school, roles: [studentRoles], externalId: userExternalId });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createMock } from '@golevelup/ts-jest';
import { UnauthorizedException } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { SystemEntity } from '@shared/domain';
import { systemFactory } from '@shared/testing';
import { systemEntityFactory } from '@shared/testing';
import { LegacyLogger } from '@src/core/logger';
import { LdapService } from './ldap.service';

Expand Down Expand Up @@ -59,7 +59,7 @@ describe('LdapService', () => {
describe('checkLdapCredentials', () => {
describe('when credentials are correct', () => {
it('should login successfully', async () => {
const system: SystemEntity = systemFactory.withLdapConfig().buildWithId();
const system: SystemEntity = systemEntityFactory.withLdapConfig().buildWithId();
await expect(
ldapService.checkLdapCredentials(system, 'connectSucceeds', 'mockPassword')
).resolves.not.toThrow();
Expand All @@ -68,7 +68,7 @@ describe('LdapService', () => {

describe('when no ldap config is provided', () => {
it('should throw error', async () => {
const system: SystemEntity = systemFactory.buildWithId();
const system: SystemEntity = systemEntityFactory.buildWithId();
await expect(ldapService.checkLdapCredentials(system, 'mockUsername', 'mockPassword')).rejects.toThrow(
new Error(`no LDAP config found in system ${system.id}`)
);
Expand All @@ -77,7 +77,7 @@ describe('LdapService', () => {

describe('when user is not authorized', () => {
it('should throw unauthorized error', async () => {
const system: SystemEntity = systemFactory.withLdapConfig().buildWithId();
const system: SystemEntity = systemEntityFactory.withLdapConfig().buildWithId();
await expect(ldapService.checkLdapCredentials(system, 'mockUsername', 'mockPassword')).rejects.toThrow(
new UnauthorizedException('User could not authenticate')
);
Expand All @@ -86,7 +86,7 @@ describe('LdapService', () => {

describe('when connected flag is not set', () => {
it('should throw unauthorized error', async () => {
const system: SystemEntity = systemFactory.withLdapConfig().buildWithId();
const system: SystemEntity = systemEntityFactory.withLdapConfig().buildWithId();
await expect(ldapService.checkLdapCredentials(system, 'connectWithoutFlag', 'mockPassword')).rejects.toThrow(
new UnauthorizedException('User could not authenticate')
);
Expand Down
Loading
Loading