Skip to content

Commit

Permalink
BC-4942 - authorization reference service (#4413)
Browse files Browse the repository at this point in the history
* Split reference authorisation service from authorisation service
* Replace on some places the authorisation methodes
* Move rules into authorisation module to fix dependency issues
* Fix invalid tests
* Fix invalid imports
  • Loading branch information
CeEv authored Oct 19, 2023
1 parent fa3a4f7 commit 4e8cfa0
Show file tree
Hide file tree
Showing 120 changed files with 2,162 additions and 1,470 deletions.
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
100 changes: 0 additions & 100 deletions apps/server/src/modules/authorization/authorization.service.ts

This file was deleted.

Loading

0 comments on commit 4e8cfa0

Please sign in to comment.