Skip to content

Commit

Permalink
Merge branch 'main' into EW-838
Browse files Browse the repository at this point in the history
  • Loading branch information
alweber-cap authored Jul 19, 2024
2 parents b51838c + 2488659 commit 58f530e
Show file tree
Hide file tree
Showing 38 changed files with 939 additions and 1,945 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ spec:
git.branch: {{ SCHULCLOUD_SERVER_BRANCH_NAME }}
git.repo: {{ SCHULCLOUD_SERVER_REPO_NAME }}
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
runAsNonRoot: true
volumes:
- name: libraries-list
configMap:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ data:
EXIT_ON_ERROR: "true"
SC_DOMAIN: "{{ DOMAIN }}"
FEATURE_PROMETHEUS_METRICS_ENABLED: "true"
ETHERPAD__PAD_URI: "https://{{ DOMAIN }}/etherpad/p"
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ data:
EXIT_ON_ERROR: "true"
SC_DOMAIN: "{{ DOMAIN }}"
FEATURE_PROMETHEUS_METRICS_ENABLED: "true"
ETHERPAD__PAD_URI: "https://{{ DOMAIN }}/etherpad/p"
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ spec:
spec:
template:
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
runAsNonRoot: true
containers:
- name: delete-s3-files-cronjob
image: {{ SCHULCLOUD_SERVER_IMAGE }}:{{ SCHULCLOUD_SERVER_IMAGE_TAG }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ spec:
spec:
template:
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
runAsNonRoot: true
containers:
- name: data-deletion-trigger-cronjob
image: {{ SCHULCLOUD_SERVER_IMAGE }}:{{ SCHULCLOUD_SERVER_IMAGE_TAG }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ spec:
labels:
app: api-migration
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
runAsNonRoot: true
containers:
- name: api-migration-job
image: {{ SCHULCLOUD_SERVER_IMAGE }}:{{ SCHULCLOUD_SERVER_IMAGE_TAG }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ spec:
spec:
template:
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
runAsNonRoot: true
containers:
- name: tldraw-delete-files-cronjob
image: {{ SCHULCLOUD_SERVER_IMAGE }}:{{ SCHULCLOUD_SERVER_IMAGE_TAG }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ spec:
mountPath: /update.sh
subPath: update.sh
command: ['/bin/sh','-c']
args: ['cp /update.sh /update.run.sh && chmod +x /update.run.sh &&./update.run.sh']
args: ['cp /update.sh /update.run.sh && chmod +x /update.run.sh && ./update.run.sh']
resources:
limits:
cpu: "3000m"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Inject, Injectable } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { RawAxiosRequestConfig } from 'axios';
import cookie from 'cookie';
import { Request } from 'express';
import { ExtractJwt, JwtFromRequestFunction } from 'passport-jwt';
import { extractJwtFromHeader } from '@shared/common';
import { AuthorizationApi, AuthorizationBodyParams } from './authorization-api-client';
import { AuthorizationErrorLoggableException, AuthorizationForbiddenLoggableException } from './error';

Expand All @@ -19,9 +18,9 @@ export class AuthorizationClientAdapter {
}

public async hasPermissionsByReference(params: AuthorizationBodyParams): Promise<boolean> {
const options = this.createOptionParams(params);

try {
const options = this.createOptionParams();

const response = await this.authorizationApi.authorizationReferenceControllerAuthorizeByReference(
params,
options
Expand All @@ -34,34 +33,20 @@ export class AuthorizationClientAdapter {
}
}

private createOptionParams(params: AuthorizationBodyParams): RawAxiosRequestConfig<any> {
const jwt = this.getJWT(params);
private createOptionParams(): RawAxiosRequestConfig<any> {
const jwt = this.getJwt();
const options: RawAxiosRequestConfig<any> = { headers: { authorization: `Bearer ${jwt}` } };

return options;
}

private getJWT(params: AuthorizationBodyParams): string {
const getJWT = ExtractJwt.fromExtractors([ExtractJwt.fromAuthHeaderAsBearerToken(), this.fromCookie('jwt')]);
const jwt = getJWT(this.request) || this.request.headers.authorization;
private getJwt(): string {
const jwt = extractJwtFromHeader(this.request) || this.request.headers.authorization;

if (!jwt) {
const error = new Error('Authentication is required.');
throw new AuthorizationErrorLoggableException(error, params);
throw new Error('Authentication is required.');
}

return jwt;
}

private fromCookie(name: string): JwtFromRequestFunction {
return (request: Request) => {
let token: string | null = null;
const cookies = cookie.parse(request.headers.cookie || '');
if (cookies && cookies[name]) {
token = cookies[name];
}

return token;
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ import {
} from '@nestjs/common';
import { ApiBearerAuth } from '@nestjs/swagger';
import { Request } from 'express';
import { ExtractJwt } from 'passport-jwt';
import { extractJwtFromHeader } from '@shared/common';
import { JwtAuthGuard } from '../guard/jwt-auth.guard';
import { ICurrentUser, isICurrentUser } from '../interface/user';
import { JwtExtractor } from '../helper/jwt-extractor';

const STRATEGIES = ['jwt'] as const;
type Strategies = typeof STRATEGIES;
Expand Down Expand Up @@ -56,9 +55,8 @@ export const CurrentUser = createParamDecorator<never, never, ICurrentUser>((_,
* @requires Authenticated
*/
export const JWT = createParamDecorator<never, never, string>((_, ctx: ExecutionContext) => {
const getJWT = ExtractJwt.fromExtractors([ExtractJwt.fromAuthHeaderAsBearerToken(), JwtExtractor.fromCookie('jwt')]);
const req: Request = ctx.switchToHttp().getRequest();
const jwt = getJWT(req) || req.headers.authorization;
const jwt = extractJwtFromHeader(req) || req.headers.authorization;

if (!jwt) {
throw new UnauthorizedException('Authentication is required.');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class AuthenticationService {
async generateJwt(user: CreateJwtPayload): Promise<LoginDto> {
const jti = randomUUID();

const result: LoginDto = new LoginDto({
const result = new LoginDto({
accessToken: this.jwtService.sign(user, {
subject: user.accountId,
jwtid: jti,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { Strategy } from 'passport-jwt';
import { extractJwtFromHeader } from '@shared/common';
import { jwtConstants } from '../constants';
import { ICurrentUser } from '../interface';
import { JwtPayload } from '../interface/jwt-payload';
import { CurrentUserMapper } from '../mapper';
import { JwtExtractor } from '../helper/jwt-extractor';
import { JwtValidationAdapter } from '../helper/jwt-validation.adapter';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private readonly jwtValidationAdapter: JwtValidationAdapter) {
super({
jwtFromRequest: ExtractJwt.fromExtractors([
ExtractJwt.fromAuthHeaderAsBearerToken(),
JwtExtractor.fromCookie('jwt'),
]),
jwtFromRequest: extractJwtFromHeader,
ignoreExpiration: false,
secretOrKey: jwtConstants.secret,
...jwtConstants.jwtOptions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Account } from '@modules/account';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { GuardAgainst } from '@shared/common/utils/guard-against';
import { TypeGuard } from '@shared/common';
import { UserRepo } from '@shared/repo';
import bcrypt from 'bcryptjs';
import { Strategy } from 'passport-local';
Expand All @@ -28,13 +28,13 @@ export class LocalStrategy extends PassportStrategy(Strategy) {

if (this.configService.get('FEATURE_IDENTITY_MANAGEMENT_LOGIN_ENABLED')) {
const jwt = await this.idmOauthService.resourceOwnerPasswordGrant(username, password);
GuardAgainst.nullOrUndefined(jwt, new UnauthorizedException());
TypeGuard.checkNotNullOrUndefined(jwt, new UnauthorizedException());
} else {
const accountPassword = GuardAgainst.nullOrUndefined(account.password, new UnauthorizedException());
const accountPassword = TypeGuard.checkNotNullOrUndefined(account.password, new UnauthorizedException());
await this.checkCredentials(password, accountPassword, account);
}

const accountUserId = GuardAgainst.nullOrUndefined(
const accountUserId = TypeGuard.checkNotNullOrUndefined(
account.userId,
new Error(`login failing, because account ${account.id} has no userId`)
);
Expand All @@ -44,8 +44,8 @@ export class LocalStrategy extends PassportStrategy(Strategy) {
}

private cleanupInput(username?: string, password?: string): { username: string; password: string } {
username = GuardAgainst.nullOrUndefined(username, new UnauthorizedException());
password = GuardAgainst.nullOrUndefined(password, new UnauthorizedException());
username = TypeGuard.checkNotNullOrUndefined(username, new UnauthorizedException());
password = TypeGuard.checkNotNullOrUndefined(password, new UnauthorizedException());
username = this.authenticationService.normalizeUsername(username);
password = this.authenticationService.normalizePassword(password);
return { username, password };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { WsException } from '@nestjs/websockets';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { JwtExtractor } from '@shared/common';
import { jwtConstants } from '../constants';
import { ICurrentUser } from '../interface';
import { JwtPayload } from '../interface/jwt-payload';
import { CurrentUserMapper } from '../mapper';
import { JwtExtractor } from '../helper/jwt-extractor';
import { JwtValidationAdapter } from '../helper/jwt-validation.adapter';

@Injectable()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,10 @@ describe(`deletionExecution (api)`, () => {

describe('executeDeletions', () => {
describe('when execute deletionRequests with default limit', () => {
jest.setTimeout(20000);
it('should return status 204', async () => {
const response = await testApiClient.post('');
expect(response.status).toEqual(204);
});
}, 20000);
});

describe('without token', () => {
Expand Down

This file was deleted.

This file was deleted.

1 change: 0 additions & 1 deletion apps/server/src/modules/provisioning/loggable/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export * from './user-for-group-not-found.loggable';
export * from './school-for-group-not-found.loggable';
export * from './group-role-unknown.loggable';
export { EmailAlreadyExistsLoggable } from './email-already-exists.loggable';
export { SchoolExternalToolCreatedLoggable } from './school-external-tool-created.loggable';
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ describe(SchulconnexUserProvisioningService.name, () => {
let userService: DeepMocked<UserService>;
let roleService: DeepMocked<RoleService>;
let accountService: DeepMocked<AccountService>;
let logger: DeepMocked<Logger>;

beforeAll(async () => {
module = await Test.createTestingModule({
Expand Down Expand Up @@ -51,7 +50,6 @@ describe(SchulconnexUserProvisioningService.name, () => {
userService = module.get(UserService);
roleService = module.get(RoleService);
accountService = module.get(AccountService);
logger = module.get(Logger);
});

afterAll(async () => {
Expand Down Expand Up @@ -140,27 +138,6 @@ describe(SchulconnexUserProvisioningService.name, () => {
});
});

it('should call user service to check uniqueness of email', async () => {
const { externalUser, schoolId, systemId } = setupUser();

userService.findByExternalId.mockResolvedValue(null);

await service.provisionExternalUser(externalUser, systemId, schoolId);

expect(userService.isEmailUniqueForExternal).toHaveBeenCalledWith(externalUser.email, undefined);
});

it('should call the user service to save the user', async () => {
const { externalUser, schoolId, savedUser, systemId } = setupUser();

userService.findByExternalId.mockResolvedValue(null);
userService.isEmailUniqueForExternal.mockResolvedValue(true);

await service.provisionExternalUser(externalUser, systemId, schoolId);

expect(userService.save).toHaveBeenCalledWith(new UserDO({ ...savedUser, id: undefined }));
});

it('should return the saved user', async () => {
const { externalUser, schoolId, savedUser, systemId } = setupUser();

Expand Down Expand Up @@ -198,35 +175,9 @@ describe(SchulconnexUserProvisioningService.name, () => {
await expect(promise).rejects.toThrow(UnprocessableEntityException);
});
});

describe('when the external user has an email, that already exists', () => {
it('should log EmailAlreadyExistsLoggable', async () => {
const { externalUser, systemId, schoolId } = setupUser();

userService.findByExternalId.mockResolvedValue(null);
userService.isEmailUniqueForExternal.mockResolvedValue(false);

await service.provisionExternalUser(externalUser, systemId, schoolId);

expect(logger.warning).toHaveBeenCalledWith({
email: externalUser.email,
});
});
});
});

describe('when the user already exists', () => {
it('should call user service to check uniqueness of email', async () => {
const { externalUser, schoolId, systemId, existingUser } = setupUser();

userService.findByExternalId.mockResolvedValue(existingUser);
userService.isEmailUniqueForExternal.mockResolvedValue(true);

await service.provisionExternalUser(externalUser, systemId, schoolId);

expect(userService.isEmailUniqueForExternal).toHaveBeenCalledWith(externalUser.email, existingUser.externalId);
});

it('should call the user service to save the user', async () => {
const { externalUser, schoolId, existingUser, systemId } = setupUser();

Expand Down
Loading

0 comments on commit 58f530e

Please sign in to comment.