From a0b4488a76fdd9eefcdcb9d6cbecd90684b39b0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A1muel=20Fekete?= Date: Wed, 14 Aug 2024 23:03:02 +0200 Subject: [PATCH] use passport-authsch lib for authentication --- package-lock.json | 76 +++++++----------------------------- package.json | 3 +- src/auth/auth.service.ts | 17 ++++---- src/auth/authsch.strategy.ts | 34 ++++++---------- src/auth/oauthuser.ts | 20 ---------- 5 files changed, 34 insertions(+), 116 deletions(-) delete mode 100644 src/auth/oauthuser.ts diff --git a/package-lock.json b/package-lock.json index 4d67409..12a6621 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@casl/ability": "^6.3.3", "@casl/prisma": "^1.4.1", + "@kir-dev/passport-authsch": "^2.0.3", "@nestjs/axios": "^3.0.0", "@nestjs/common": "^10.0.2", "@nestjs/core": "^10.0.2", @@ -29,7 +30,6 @@ "ics": "^3.1.0", "papaparse": "^5.3.2", "passport-jwt": "^4.0.0", - "passport-oauth2": "^1.6.1", "puppeteer": "^20.7.4", "reflect-metadata": "^0.2.0", "rimraf": "^5.0.0", @@ -46,7 +46,6 @@ "@types/node": "^20.0.0", "@types/papaparse": "^5.3.7", "@types/passport-jwt": "^4.0.0", - "@types/passport-oauth2": "^1.4.11", "@types/supertest": "^6.0.0", "@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/parser": "^8.0.0", @@ -1643,6 +1642,20 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@kir-dev/passport-authsch": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@kir-dev/passport-authsch/-/passport-authsch-2.0.3.tgz", + "integrity": "sha512-UDOtR/kQdRvPlrMfCCV22odzRUvQ3dL7yvhJzwqs99SmuEr4C7wE+pKQpXFAN0LqXuxCeJp3kWaN5Z/otl6c+w==", + "license": "MIT", + "dependencies": { + "axios": "^1.7.4", + "passport-strategy": "^1.0.0" + }, + "engines": { + "node": "^20.0.0", + "npm": "^10.5.1" + } + }, "node_modules/@ljharb/through": { "version": "2.3.12", "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.12.tgz", @@ -2541,15 +2554,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@types/oauth": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@types/oauth/-/oauth-0.9.1.tgz", - "integrity": "sha512-a1iY62/a3yhZ7qH7cNUsxoI3U/0Fe9+RnuFrpTKr+0WVOzbKlSLojShCKe20aOD1Sppv+i8Zlq0pLDuTJnwS4A==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/papaparse": { "version": "5.3.14", "resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.3.14.tgz", @@ -2578,17 +2582,6 @@ "@types/passport-strategy": "*" } }, - "node_modules/@types/passport-oauth2": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@types/passport-oauth2/-/passport-oauth2-1.4.15.tgz", - "integrity": "sha512-9cUTP/HStNSZmhxXGuRrBJfEWzIEJRub2eyJu3CvkA+8HAMc9W3aKdFhVq+Qz1hi42qn+GvSAnz3zwacDSYWpw==", - "dev": true, - "dependencies": { - "@types/express": "*", - "@types/oauth": "*", - "@types/passport": "*" - } - }, "node_modules/@types/passport-strategy": { "version": "0.2.35", "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.35.tgz", @@ -3335,7 +3328,6 @@ "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", "license": "MIT", - "peer": true, "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -3462,14 +3454,6 @@ } ] }, - "node_modules/base64url": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", - "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/basic-ftp": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.3.tgz", @@ -5411,7 +5395,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=4.0" }, @@ -7578,11 +7561,6 @@ "node": ">=8" } }, - "node_modules/oauth": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.10.0.tgz", - "integrity": "sha512-1orQ9MT1vHFGQxhuy7E/0gECD3fd2fCC+PIX+/jgmU/gI3EpRocXtmtvxCO5x3WZ443FLTLFWNDjl5MPJf9u+Q==" - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -7839,25 +7817,6 @@ "passport-strategy": "^1.0.0" } }, - "node_modules/passport-oauth2": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.8.0.tgz", - "integrity": "sha512-cjsQbOrXIDE4P8nNb3FQRCCmJJ/utnFKEz2NX209f7KOHPoX18gF7gBzBbLLsj2/je4KrgiwLLGjf0lm9rtTBA==", - "dependencies": { - "base64url": "3.x.x", - "oauth": "0.10.x", - "passport-strategy": "1.x.x", - "uid2": "0.0.x", - "utils-merge": "1.x.x" - }, - "engines": { - "node": ">= 0.4.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/jaredhanson" - } - }, "node_modules/passport-strategy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", @@ -9661,11 +9620,6 @@ "node": ">=8" } }, - "node_modules/uid2": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.4.tgz", - "integrity": "sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==" - }, "node_modules/unbzip2-stream": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", diff --git a/package.json b/package.json index 5a8e17c..b122df6 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "dependencies": { "@casl/ability": "^6.3.3", "@casl/prisma": "^1.4.1", + "@kir-dev/passport-authsch": "^2.0.3", "@nestjs/axios": "^3.0.0", "@nestjs/common": "^10.0.2", "@nestjs/core": "^10.0.2", @@ -43,7 +44,6 @@ "ics": "^3.1.0", "papaparse": "^5.3.2", "passport-jwt": "^4.0.0", - "passport-oauth2": "^1.6.1", "puppeteer": "^20.7.4", "reflect-metadata": "^0.2.0", "rimraf": "^5.0.0", @@ -60,7 +60,6 @@ "@types/node": "^20.0.0", "@types/papaparse": "^5.3.7", "@types/passport-jwt": "^4.0.0", - "@types/passport-oauth2": "^1.4.11", "@types/supertest": "^6.0.0", "@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/parser": "^8.0.0", diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index 877af86..fd9b452 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -1,3 +1,4 @@ +import { AuthSchProfile } from '@kir-dev/passport-authsch' import { Injectable, InternalServerErrorException, @@ -7,8 +8,6 @@ import { JwtService } from '@nestjs/jwt' import { User } from '@prisma/client' import { UserEntity } from 'src/users/dto/UserEntity.dto' import { UsersService } from '../users/users.service' -import { OAuthUser } from './oauthuser' - @Injectable() export class AuthService { private readonly logger = new Logger(AuthService.name) @@ -18,20 +17,18 @@ export class AuthService { private readonly jwtService: JwtService, ) {} - async findOrCreateUser(oAuthUser: OAuthUser): Promise { + async findOrCreateUser(oAuthUser: AuthSchProfile): Promise { try { - const user = await this.usersService.findByAuthSchId( - oAuthUser.internal_id, - ) + const user = await this.usersService.findByAuthSchId(oAuthUser.authSchId) if (user) { return user } const newUser = await this.usersService.create({ - authSchId: oAuthUser.internal_id, - firstName: oAuthUser.givenName, - fullName: oAuthUser.displayName, - email: oAuthUser.mail, + authSchId: oAuthUser.authSchId, + firstName: oAuthUser.firstName, + fullName: oAuthUser.fullName, + email: oAuthUser.email, }) this.logger.log(`User #${newUser.id} created`) diff --git a/src/auth/authsch.strategy.ts b/src/auth/authsch.strategy.ts index 3618a2e..1202815 100644 --- a/src/auth/authsch.strategy.ts +++ b/src/auth/authsch.strategy.ts @@ -1,38 +1,26 @@ -import { HttpService } from '@nestjs/axios' +import { + AuthSchProfile, + AuthSchScope, + Strategy, +} from '@kir-dev/passport-authsch' import { Injectable, Logger } from '@nestjs/common' import { PassportStrategy } from '@nestjs/passport' -import { Strategy } from 'passport-oauth2' -import { firstValueFrom } from 'rxjs' import { UserEntity } from 'src/users/dto/UserEntity.dto' import { AuthService } from './auth.service' -import { OAuthUser } from './oauthuser' - -const AUTHSCH_HOST = 'https://auth.sch.bme.hu' @Injectable() -export class AuthschStrategy extends PassportStrategy(Strategy, 'authsch') { +export class AuthschStrategy extends PassportStrategy(Strategy) { private readonly logger = new Logger(AuthschStrategy.name) - constructor( - private httpService: HttpService, - private authService: AuthService, - ) { + constructor(private authService: AuthService) { super({ - authorizationURL: `${AUTHSCH_HOST}/site/login`, - tokenURL: `${AUTHSCH_HOST}/oauth2/token`, - clientID: process.env.AUTHSCH_CLIENT_ID, + clientId: process.env.AUTHSCH_CLIENT_ID, clientSecret: process.env.AUTHSCH_CLIENT_SECRET, - scope: ['basic', 'givenName', 'displayName', 'mail'], // ?? niifEduPersonAttendedCourse = hallgatott tárgyak - // Hallgató által jelenleg hallgatott kurzusok kódjai. Példa: "BMEVIAUA218;BMEVIIIA316" + scopes: [AuthSchScope.PROFILE, AuthSchScope.EMAIL], }) } - async validate(accessToken: string): Promise { - const { data: oAuthUser } = await firstValueFrom( - this.httpService.get( - `${AUTHSCH_HOST}/api/profile?access_token=${accessToken}`, - ), - ) - const dbUser = await this.authService.findOrCreateUser(oAuthUser) + async validate(userProfile: AuthSchProfile): Promise { + const dbUser = await this.authService.findOrCreateUser(userProfile) this.logger.debug('DbUser in validate' + JSON.stringify(dbUser, null, 2)) return dbUser } diff --git a/src/auth/oauthuser.ts b/src/auth/oauthuser.ts deleted file mode 100644 index 83e9391..0000000 --- a/src/auth/oauthuser.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { IsEmail, IsNotEmpty, IsOptional, IsUUID } from 'class-validator' - -export class OAuthUser { - @IsNotEmpty() - displayName: string - - @IsNotEmpty() - givenName: string - - @IsUUID('all') - internal_id: string - - @IsEmail() - @IsOptional() - mail?: string - - constructor(partial: Partial) { - Object.assign(this, partial) - } -}