Skip to content

Commit

Permalink
local login with tsp via Keycloak works
Browse files Browse the repository at this point in the history
  • Loading branch information
psachmann committed Oct 11, 2024
1 parent 76d2992 commit bf2320f
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@ export class ClassSourceOptions {
get tspUid(): string | undefined {
return this.props.tspUid;
}

set tspUid(tspUid: string | undefined) {
this.props.tspUid = tspUid;
}
}
3 changes: 2 additions & 1 deletion apps/server/src/modules/class/repo/classes.repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ export class ClassesRepo {
? classes.map((aclass: Class): ClassEntity => ClassMapper.mapToEntity(aclass))
: [ClassMapper.mapToEntity(classes)];

await this.em.persistAndFlush(entities);
await this.em.upsertMany(entities);
await this.em.flush();
}

async updateMany(classes: Class[]): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export class ExternalClassDto {
public readonly externalId: string;

public readonly name?: string;
public readonly name: string;

constructor(props: Readonly<ExternalClassDto>) {
this.externalId = props.externalId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,7 @@ export class TspProvisioningService {
if (currentClass) {
// Case: Class exists -> update class
currentClass.schoolId = school.id;
if (clazz.name) {
currentClass.name = clazz.name;
}
currentClass.name = clazz.name;
currentClass.year = school.currentYear?.id;
currentClass.source = this.ENTITY_SOURCE;
currentClass.sourceOptions = new ClassSourceOptions({ tspUid: clazz.externalId });
Expand Down Expand Up @@ -115,7 +113,7 @@ export class TspProvisioningService {
roleRefs: RoleReference[],
schoolId: string
): Promise<UserDO> {
if (!externalUser.firstName || !externalUser.lastName || !externalUser.email) {
if (!externalUser.firstName || !externalUser.lastName) {
throw new BadDataLoggableException('User firstname, lastname or email is missing', { externalUser });
}

Expand All @@ -124,8 +122,9 @@ export class TspProvisioningService {
schoolId,
firstName: externalUser.firstName,
lastName: externalUser.lastName,
email: externalUser.email,
email: this.createTspEmail(externalUser.firstName, externalUser.lastName),
birthday: externalUser.birthday,
externalId: externalUser.externalId,
});
const savedUser = await this.userService.save(newUser);

Expand All @@ -137,7 +136,10 @@ export class TspProvisioningService {

const account = await this.accountService.findByUserId(user.id);

if (!account) {
if (account) {
await account.update(new AccountSave({ userId: user.id, systemId, username: user.email, activated: true }));
await this.accountService.save(account);
} else {
await this.accountService.saveWithValidation(
new AccountSave({
userId: user.id,
Expand All @@ -146,10 +148,6 @@ export class TspProvisioningService {
activated: true,
})
);
} else {
account.username = user.email;

await this.accountService.saveWithValidation(account);
}
}

Expand All @@ -159,4 +157,10 @@ export class TspProvisioningService {

return roleRefs;
}

private createTspEmail(firstname: string, lastname: string): string {
const email = `${firstname}.${lastname}@tsp.de`;

return email.toLowerCase();
}
}
Original file line number Diff line number Diff line change
@@ -1,33 +1,34 @@
import { IsString, IsOptional } from 'class-validator';
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
import { JwtPayload } from 'jsonwebtoken';

export class TspJwtPayload implements JwtPayload {
@IsString()
@IsNotEmpty()
public sub!: string;

@IsOptional()
@IsString()
public sid: string | undefined;

@IsOptional()
@IsString()
public ptscListRolle: string | undefined;
@IsNotEmpty()
public ptscListRolle!: string;

@IsOptional()
@IsString()
public personVorname: string | undefined;
@IsNotEmpty()
public personVorname!: string;

@IsOptional()
@IsString()
public personNachname: string | undefined;
@IsNotEmpty()
public personNachname!: string;

@IsOptional()
@IsString()
public ptscSchuleNummer: string | undefined;
@IsNotEmpty()
public ptscSchuleNummer!: string;

@IsOptional()
@IsString()
public ptscListKlasseId: string | undefined;
@IsNotEmpty()
public ptscListKlasseId!: string;

constructor(data: Partial<TspJwtPayload>) {
Object.assign(this, data);
Expand Down
26 changes: 18 additions & 8 deletions apps/server/src/modules/provisioning/strategy/tsp/tsp.strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@ import { TspJwtPayload } from './tsp.jwt.payload';

@Injectable()
export class TspProvisioningStrategy extends ProvisioningStrategy {
RoleMapping: Record<string, RoleName> = {
lehrer: RoleName.TEACHER,
schueler: RoleName.STUDENT,
admin: RoleName.ADMINISTRATOR,
};

constructor(private readonly provisioningService: TspProvisioningService) {
super();
}
Expand All @@ -51,15 +45,15 @@ export class TspProvisioningStrategy extends ProvisioningStrategy {
externalId: payload.sub,
firstName: payload.personVorname,
lastName: payload.personNachname,
roles: (payload.ptscListRolle ?? '').split(',').map((tspRole) => this.RoleMapping[tspRole]),
roles: payload.ptscListRolle.split(',').map((role) => this.mapRoles(role)),
});

const externalSchoolDto = new ExternalSchoolDto({
externalId: payload.ptscSchuleNummer || '',
});

const externalClassDtoList = payload.ptscListKlasseId
? [new ExternalClassDto({ externalId: payload.ptscListKlasseId })]
? [new ExternalClassDto({ externalId: payload.ptscListKlasseId, name: '' })]
: [];

const oauthDataDto = new OauthDataDto({
Expand All @@ -83,4 +77,20 @@ export class TspProvisioningStrategy extends ProvisioningStrategy {

return new ProvisioningDto({ externalUserId: user.externalId || data.externalUser.externalId });
}

private mapRoles(tspRole: string): RoleName {
// TODO: Are all roles mapped correctly?
const roleNameLowerCase = tspRole.toLowerCase();

switch (roleNameLowerCase) {
case 'lehrer':
return RoleName.TEACHER;
case 'schueler':
return RoleName.STUDENT;
case 'administrator':
return RoleName.ADMINISTRATOR;
default:
return RoleName.USER;
}
}
}

0 comments on commit bf2320f

Please sign in to comment.