Skip to content

Commit

Permalink
Merge branch 'main' into N21-1264-new-class-page-extension
Browse files Browse the repository at this point in the history
  • Loading branch information
arnegns committed Oct 20, 2023
2 parents a71b361 + 0ab2dfb commit 1974338
Show file tree
Hide file tree
Showing 242 changed files with 3,624 additions and 2,446 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Body, Controller, Delete, Get, Param, Patch, Query } from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { EntityNotFoundError, ForbiddenOperationError, ValidationError } from '@shared/common';
import { ICurrentUser } from '@src/modules/authentication';
import { Authenticate, CurrentUser } from '@src/modules/authentication/decorator/auth.decorator';
import { ICurrentUser, Authenticate, CurrentUser } from '@src/modules/authentication';
import { AccountUc } from '../uc/account.uc';
import {
AccountByIdBodyParams,
Expand Down
1 change: 1 addition & 0 deletions apps/server/src/modules/account/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './account.module';
export * from './account-config';
export { AccountService } from './services';
1 change: 1 addition & 0 deletions apps/server/src/modules/account/services/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './account.service';
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Body, Controller, HttpCode, HttpStatus, Post, UseGuards } from '@nestjs
import { AuthGuard } from '@nestjs/passport';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { ForbiddenOperationError, ValidationError } from '@shared/common';
import { CurrentUser } from '../decorator/auth.decorator';
import { CurrentUser } from '../decorator';
import type { ICurrentUser, OauthCurrentUser } from '../interface';
import { LoginDto } from '../uc/dto';
import { LoginUc } from '../uc/login.uc';
Expand Down
1 change: 1 addition & 0 deletions apps/server/src/modules/authentication/decorator/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './auth.decorator';
4 changes: 4 additions & 0 deletions apps/server/src/modules/authentication/errors/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './brute-force.error';
export * from './ldap-connection.error';
export * from './school-in-migration.error';
export * from './unauthorized.loggable-exception';
4 changes: 2 additions & 2 deletions apps/server/src/modules/authentication/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from './interface';
export * from './guard/jwt-auth.guard';
export { ICurrentUser } from './interface';
export { JWT, CurrentUser, Authenticate } from './decorator';
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface CreateJwtPayload {
roles: string[];
systemId?: string; // without this the user needs to change his PW during first login
support?: boolean;
// support UserId is missed see featherJS
}

export interface JwtPayload extends CreateJwtPayload {
Expand Down
24 changes: 0 additions & 24 deletions apps/server/src/modules/authentication/interface/user.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,5 @@
import { EntityId } from '@shared/domain';

export interface IRole {
name: string;

id: string;
}

export interface IResolvedUser {
firstName: string;

lastName: string;

id: string;

createdAt: Date;

updatedAt: Date;

roles: IRole[];

permissions: string[];

schoolId: string;
}

export interface ICurrentUser {
/** authenticated users id */
userId: EntityId;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
import { AccountService } from '@src/modules/account/services/account.service';
import { AccountService } from '@src/modules/account';
// invalid import
import { AccountDto } from '@src/modules/account/services/dto';
import { JwtValidationAdapter } from '@src/modules/authentication/strategy/jwt-validation.adapter';
// invalid import, can produce dependency cycles
import type { IServerConfig } from '@src/modules/server';
import { randomUUID } from 'crypto';
import jwt, { JwtPayload } from 'jsonwebtoken';
import { BruteForceError } from '../errors/brute-force.error';
import { UnauthorizedLoggableException } from '../errors/unauthorized.loggable-exception';
import { JwtValidationAdapter } from '../strategy/jwt-validation.adapter';
import { BruteForceError, UnauthorizedLoggableException } from '../errors';
import { CreateJwtPayload } from '../interface/jwt-payload';
import { LoginDto } from '../uc/dto';

Expand Down
101 changes: 44 additions & 57 deletions apps/server/src/modules/authorization/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,17 +132,7 @@ When calling other internal micro service for already authorized operations plea
// next orchestration steps
```
### Example 2 - Execute a Single Operation with Loading Resources
```javascript
// If you don't have an entity but an entity type and id, you can check permission by reference
await this.authorizationService.checkPermissionByReferences(userId, AllowedEntity.course, courseId, AuthorizationContextBuilder.read([]));
// or
await this.authorizationService.hasPermissionByReferences(userId, AllowedEntity.course, courseId, AuthorizationContextBuilder.read([]));
// next orchestration steps
```
### Example 3 - Set Permission(s) of User as Required
### Example 2 - Set Permission(s) of User as Required
```javascript
// Multiple permissions can be added. For a successful authorization, the user need all of them.
Expand Down Expand Up @@ -173,14 +163,13 @@ this.authorizationService.hasPermission(userId, course, PermissionContexts.creat
```ts
async createSchoolBySuperhero(userId: EntityId, params: { name: string }) {

const user = this.authorizationService.getUserWithPermissions(userId);
this.authorizationService.hasAllPermissions(user, [Permission.SCHOOL_CREATE]);

const school = new School(params);
const user = this.authorizationService.getUserWithPermissions(userId);
this.authorizationService.hasAllPermissions(user, [Permission.SCHOOL_CREATE]);

await this.schoolService.save(school);
const school = new School(params);
await this.schoolService.save(school);

return true;
return true;
}

```
Expand All @@ -191,15 +180,15 @@ async createSchoolBySuperhero(userId: EntityId, params: { name: string }) {

async createUserByAdmin(userId: EntityId, params: { email: string, firstName: string, lastName: string, schoolId: EntityId }) {

const user = this.authorizationService.getUserWithPermissions(userId);

await this.authorizationService.checkPermissionByReferences(userId, AllowedEntity.school, schoolId, AuthorizationContextBuilder.write([Permission.INSTANCE, Permission.CREATE_USER]));

const newUser = new User(params)
const user = this.authorizationService.getUserWithPermissions(userId);

const context = AuthorizationContextBuilder.write([Permission.INSTANCE, Permission.CREATE_USER])
await this.authorizationService.checkPermission(user, school, context);

await this.userService.save(newUser);
const newUser = new User(params)
await this.userService.save(newUser);

return true;
return true;
}

```
Expand All @@ -210,18 +199,17 @@ async createUserByAdmin(userId: EntityId, params: { email: string, firstName: st
// admin
async editCourseByAdmin(userId: EntityId, params: { courseId: EntityId, description: string }) {

const course = this.courseService.getCourse(params.courseId);
const user = this.authorizationService.getUserWithPermissions(userId);

const school = course.school

this.authorizationService.hasPermissions(user, school, [Permission.INSTANCE, Permission.COURSE_EDIT]);
const course = this.courseService.getCourse(params.courseId);
const user = this.authorizationService.getUserWithPermissions(userId);
const school = course.school;

course.description = params.description;
const context = AuthorizationContextBuilder.write([Permission.INSTANCE, Permission.CREATE_USER]);
this.authorizationService.checkPermissions(user, school, context);

await this.courseService.save(course);
course.description = params.description;
await this.courseService.save(course);

return true;
return true;
}

```
Expand All @@ -234,18 +222,17 @@ async createCourse(userId: EntityId, params: { schoolId: EntityId }) {
const user = this.authorizationService.getUserWithPermissions(userId);
const school = this.schoolService.getSchool(params.schoolId);

this.authorizationService.checkPermission(user, school
{
action: Actions.write,
requiredPermissions: [Permission.COURSE_CREATE],
}
);
this.authorizationService.checkPermission(user, school
{
action: Actions.write,
requiredPermissions: [Permission.COURSE_CREATE],
}
);

const course = new Course({ school });
const course = new Course({ school });
await this.courseService.saveCourse(course);

await this.courseService.saveCourse(course);

return course;
return course;
}

```
Expand All @@ -255,21 +242,20 @@ async createCourse(userId: EntityId, params: { schoolId: EntityId }) {
```ts
// User can create a lesson to course, so you have a courseId
async createLesson(userId: EntityId, params: { courseId: EntityId }) {
const course = this.courseService.getCourse(params.courseId);
const user = this.authorizationService.getUserWithPermissions(userId);
const course = this.courseService.getCourse(params.courseId);
const user = this.authorizationService.getUserWithPermissions(userId);
// check authorization for user and course
this.authorizationService.checkPermission(user, course
{
action: Actions.write,
requiredPermissions: [Permission.COURSE_EDIT],
}
);

const lesson = new Lesson({course});
this.authorizationService.checkPermission(user, course
{
action: Actions.write,
requiredPermissions: [Permission.COURSE_EDIT],
}
);

await this.lessonService.saveLesson(lesson);
const lesson = new Lesson({course});
await this.lessonService.saveLesson(lesson);

return true;
return true;
}
```
Expand Down Expand Up @@ -345,8 +331,9 @@ The authorization module is the core of authorization. It collects all needed in
### Reference.loader
For situations where only the id and the domain object (string) type is known, it is possible to use the \*ByReferences methods.
They load the reference directly.
It should be use only inside of the authorization module.
It is use to load registrated ressouces by the id and name of the ressource.
This is needed to solve the API requests from external services. (API implementation is missing for now)
> Please keep in mind that it can have an impact on the performance if you use it wrongly.
> We keep it as a seperate method to avoid the usage in areas where the domain object should exist, because we see the risk that a developer could be tempted by the ease of only passing the id.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { forwardRef, Module } from '@nestjs/common';
import {
CourseGroupRepo,
CourseRepo,
LessonRepo,
SchoolExternalToolRepo,
LegacySchoolRepo,
SubmissionRepo,
TaskRepo,
TeamsRepo,
UserRepo,
} from '@shared/repo';
import { ToolModule } from '@src/modules/tool';
import { LoggerModule } from '@src/core/logger';
import { BoardModule } from '@src/modules/board';
import { ReferenceLoader, AuthorizationReferenceService, AuthorizationHelper } from './domain';
import { AuthorizationModule } from './authorization.module';

/**
* This module is part of an intermediate state. In the future it should be replaced by an AuthorizationApiModule.
* For now it is used where the authorization itself needs to load data from the database.
* Avoid using this module and load the needed data in your use cases and then use the normal AuthorizationModule!
*/
@Module({
// TODO: remove forwardRef to TooModule N21-1055
imports: [AuthorizationModule, forwardRef(() => ToolModule), forwardRef(() => BoardModule), LoggerModule],
providers: [
AuthorizationHelper,
ReferenceLoader,
UserRepo,
CourseRepo,
CourseGroupRepo,
TaskRepo,
LegacySchoolRepo,
LessonRepo,
TeamsRepo,
SubmissionRepo,
SchoolExternalToolRepo,
AuthorizationReferenceService,
],
exports: [AuthorizationReferenceService],
})
export class AuthorizationReferenceModule {}
69 changes: 31 additions & 38 deletions apps/server/src/modules/authorization/authorization.module.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,46 @@
import { forwardRef, Module } from '@nestjs/common';
import { ALL_RULES } from '@shared/domain/rules';
import { Module } from '@nestjs/common';
import { UserRepo } from '@shared/repo';
import { LoggerModule } from '@src/core/logger';
import { FeathersModule } from '@shared/infra/feathers';
import {
CourseGroupRepo,
CourseRepo,
LessonRepo,
SchoolExternalToolRepo,
LegacySchoolRepo,
SubmissionRepo,
TaskRepo,
TeamsRepo,
UserRepo,
} from '@shared/repo';
import { LoggerModule } from '@src/core/logger';
import { LegacySchoolModule } from '@src/modules/legacy-school';
import { ToolModule } from '@src/modules/tool';
import { BoardModule } from '../board';
import { AuthorizationHelper } from './authorization.helper';
import { AuthorizationService } from './authorization.service';
BoardDoRule,
ContextExternalToolRule,
CourseGroupRule,
CourseRule,
LessonRule,
SchoolExternalToolRule,
SubmissionRule,
TaskRule,
TeamRule,
UserRule,
UserLoginMigrationRule,
LegacySchoolRule,
} from './domain/rules';
import { AuthorizationHelper, AuthorizationService, RuleManager } from './domain';
import { FeathersAuthorizationService, FeathersAuthProvider } from './feathers';
import { ReferenceLoader } from './reference.loader';
import { RuleManager } from './rule-manager';

@Module({
// TODO: remove forwardRef to TooModule N21-1055
imports: [
FeathersModule,
LoggerModule,
LegacySchoolModule,
forwardRef(() => ToolModule),
forwardRef(() => BoardModule),
],
imports: [FeathersModule, LoggerModule],
providers: [
FeathersAuthorizationService,
FeathersAuthProvider,
AuthorizationService,
...ALL_RULES,
ReferenceLoader,
UserRepo,
CourseRepo,
CourseGroupRepo,
TaskRepo,
LegacySchoolRepo,
LessonRepo,
TeamsRepo,
SubmissionRepo,
SchoolExternalToolRepo,
RuleManager,
AuthorizationHelper,
// rules
BoardDoRule,
ContextExternalToolRule,
CourseGroupRule,
CourseRule,
LessonRule,
SchoolExternalToolRule,
SubmissionRule,
TaskRule,
TeamRule,
UserRule,
UserLoginMigrationRule,
LegacySchoolRule,
],
exports: [FeathersAuthorizationService, AuthorizationService],
})
Expand Down
Loading

0 comments on commit 1974338

Please sign in to comment.