clayrisser / nestjs-keycloak

nestjs module for authenticating keycloak
23 stars 2 forks source link

Type error on init (version 2.1.3) #4

Open H256 opened 2 years ago

H256 commented 2 years ago

Hi,

first of all thanks for this nice module! 👍🏻

Somehow in the latest 2.0.99 the module init is broken. We're getting a TypeError Exception on the module init.

Could you take a look at it?

Configuration and register of the module in our code hasn't changed, we only updated to latest version available from NPM. Last working version for us is 2.0.90. Maybe we're missing something on the config part now?

I've checked that our .env is ok and the values are there...

Registration part

KeycloakModule.registerAsync({
      imports: [
        ConfigModule.forRoot({
          envFilePath: ['keycloak-client.env', 'keycloak-client.example.env'],
        }),
      ],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        baseUrl: `${config.get('BASE_URL')}`,
        clientId: config.get('CLIENT_ID') || '',
        clientSecret: config.get('SECRET') || '',
        realm: config.get('REALM') || '',
      }),
    }),

Stacktrace

TypeError: Cannot convert a Symbol value to a string
    at RegExp.test (<anonymous>)
    at KeycloakRegisterService.reduce (C:\nestproject\node_modules\nestjs-keycloak\src\keycloakRegister.service.ts:97:29)
    at Array.reduce (<anonymous>)
    at KeycloakRegisterService.providers (C:\nestproject\node_modules\nestjs-keycloak\src\keycloakRegister.service.ts:92:10)
    at KeycloakRegisterService.authorizationCallbacks (C:\nestproject\node_modules\nestjs-keycloak\src\keycloakRegister.service.ts:135:15)
    at KeycloakRegisterService._callee$ (C:\nestproject\node_modules\nestjs-keycloak\src\keycloakRegister.service.ts:217:10)
    at tryCatch (C:\...\node_modules\regenerator-runtime\runtime.js:63:40)
    at Generator.invoke [as _invoke] (C:\nestproject\node_modules\regenerator-runtime\runtime.js:294:22)
    at Generator.next (C:\nestproject\node_modules\regenerator-runtime\runtime.js:119:21)
    at asyncGeneratorStep (C:\nestproject\node_modules\@babel\runtime\helpers\asyncToGenerator.js:3:24)
clayrisser commented 2 years ago

Hey @H256, I'm so sorry, I was actively working on this project yesterday. I should have been releasing using rc's. I will do that next time. I was adding a decorator to automatically create authorization code grant endpoints. It's actually super cool, you just have to add the following code . . .

import { Logger, Controller, Get } from '@nestjs/common';
import { AuthorizationCallback, Resource } from 'nestjs-keycloak';

@Resource('auth')
@Controller('auth')
export default class AuthController {
  private readonly logger = new Logger(AuthController.name);

  constructor() {}

  @Get('callback')
  @AuthorizationCallback({ destinationUri: 'http://example.com' })
  async getCallback() {}
}

Anyways, it should be stable now (as of version 2.1.3). As far as the issue you are facing, I would suggest making sure you are on the latest LTS version of node. Let me know if you are facing this issue still, and I'll dig deeper.

H256 commented 2 years ago

Hi @clayrisser, thanks for looking into this issue :) I've updated our Node to latest LTS 14.17.6 and the package to 2.1.3 - but unfortunately I'm still facing the same issue :(

I did a "quick research" (console.log line 150 in node_modules/keycloakRegister.js) and it seems that the problem has to do with the @nestjs/throttler - module that we are using in one of our modules. The name-property contains a symbol, in this case, the regex check panics.

I don't know, if this following info is enough for you to reproduce the issue:

<ref *1> InstanceWrapper {
  isAlias: false,
  scope: undefined,
  values: WeakMap { <items unknown> },
  token: Symbol(ThrottlerStorage),
  name: Symbol(ThrottlerStorage),
  metatype: [Function: useFactory],
  inject: [ 'THROTTLER:MODULE_OPTIONS' ],
  host: Module {
    _metatype: [class ThrottlerModule],
    container: NestContainer {
      _applicationConfig: [ApplicationConfig],
      globalModules: [Set],
      moduleTokenFactory: [ModuleTokenFactory],
      moduleCompiler: [ModuleCompiler],
      modules: [ModulesContainer [Map]],
      dynamicModulesMetadata: [Map],
      internalProvidersStorage: [InternalProvidersStorage],
      internalCoreModule: [Module]
    },
    _imports: Set(7) {
      [Module],
      [Module],
      [Module],
      [Module],
      [Module],
      [Module],
      [Module]
    },
    _providers: Map(5) {
      [class ThrottlerModule] => [InstanceWrapper],
      [class ModuleRef] => [InstanceWrapper],
      [class ApplicationConfig] => [InstanceWrapper],
      'THROTTLER:MODULE_OPTIONS' => [InstanceWrapper],
      Symbol(ThrottlerStorage) => [Circular *1]
    },
    _injectables: Map(0) {},
    _middlewares: Map(0) {},
    _controllers: Map(0) {},
    _exports: Set(2) { 'THROTTLER:MODULE_OPTIONS', Symbol(ThrottlerStorage) },
    _distance: 2,
    _id: '789aee88be....',
    _token: '529514d47....'
  },
  isTreeStatic: true,
  [Symbol(instance_metadata:cache)]: { dependencies: [ [InstanceWrapper] ] },
  [Symbol(instance_metadata:id)]: '8c15082a-.......'
} object
[Nest] 6064  - 23.09.2021, 08:50:22   ERROR [Bootstrapper] TypeError: Cannot convert a Symbol value to a string
    at RegExp.test (<anonymous>)
    at KeycloakRegisterService.reduce (C:\nestproject\node_modules\nestjs-keycloak\src\keycloakRegister.service.ts:195:13)
    at Array.reduce (<anonymous>)
    at KeycloakRegisterService.providers (C:\nestproject\node_modules\nestjs-keycloak\src\keycloakRegister.service.ts:189:10)
    at KeycloakRegisterService.authorizationCallbacks (C:\nestproject\node_modules\nestjs-keycloak\src\keycloakRegister.service.ts:127:15)
    at KeycloakRegisterService.get (C:\nestproject\node_modules\nestjs-keycloak\src\keycloakRegister.service.ts:107:12)
    at KeycloakRegisterService._callee$ (C:\nestproject\node_modules\nestjs-keycloak\lib\keycloakRegister.service.js:241:78)
    at tryCatch (C:\nestproject\node_modules\regenerator-runtime\runtime.js:63:40)
    at Generator.invoke [as _invoke] (C:\nestproject\node_modules\regenerator-runtime\runtime.js:294:22)
    at Generator.next (C:\nestproject\node_modules\regenerator-runtime\runtime.js:119:21)

I am not sure, if there are more modules that show the same behavior. Basically I followed the guide on rate-limiting for controllers https://docs.nestjs.com/security/rate-limiting#rate-limiting

clayrisser commented 2 years ago

@H256 can you send me the version of nestjs you are using? Also, I'm wondering if it's a specific to windows? Could you test using OSX, Linux or the windows linux subshell?

Try using the following version of nestjs.

https://github.com/silicon-hills/nestjs-keycloak/blob/main/package.json#L51-L52

clayrisser commented 2 years ago

It appears the error is coming from the following line of code.

https://github.com/silicon-hills/nestjs-keycloak/blob/main/src/keycloakRegister.service.ts#L212

this.reflector.getAllAndMerge() is a method coming from the @nestjs/core reflection system.

https://github.com/silicon-hills/nestjs-keycloak/blob/main/src/keycloakRegister.service.ts#L76 https://github.com/silicon-hills/nestjs-keycloak/blob/main/src/keycloakRegister.service.ts#L30

I am using the reflection system to query the annotations in the controllers so I can pre populate the roles and scopes in keycloak. You might be able to temporarily bypass this issue by disabling the keycloak pre-registration (of course it won't create the roles and scopes in keycloak for you if you do that).

You can disable pre registration by setting the register config to false.

KeycloakModule.registerAsync({
  inject: [ConfigService],
  useFactory: (config: ConfigService) => {
    return {
      adminClientId: config.get('KEYCLOAK_ADMIN_CLIENT_ID') || '',
      adminPassword: config.get('KEYCLOAK_ADMIN_PASSWORD') || '',
      adminUsername: config.get('KEYCLOAK_ADMIN_USERNAME') || '',
      baseUrl: config.get('KEYCLOAK_BASE_URL') || '',
      clientId: config.get('KEYCLOAK_CLIENT_ID') || '',
      clientSecret: config.get('KEYCLOAK_CLIENT_SECRET') || '',
      realm: config.get('KEYCLOAK_REALM') || '',
      register: false
    };
  }
});
H256 commented 2 years ago

Hey @clayrisser, thanks for further investigating! 👍🏻

You can disable pre registration by setting the register config to false.

Did that - still same error :(

Additionally, I gave this a try on my WSL2 (Ubuntu 20.04). Unfortunately, same error with v2.1.3 Versions on Windows and WSL are now the same:

[Nest] 9549  - 09/24/2021, 9:32:54 AM   ERROR [Bootstrapper] TypeError: Cannot convert a Symbol value to a string
    at RegExp.test (<anonymous>)
    at KeycloakRegisterService.reduce (/home/h256/nest-project/node_modules/nestjs-keycloak/src/keycloakRegister.service.ts:194:29)
    at Array.reduce (<anonymous>)
    at KeycloakRegisterService.providers (/home/h256/nest-project/node_modules/nestjs-keycloak/src/keycloakRegister.service.ts:189:10)
    at KeycloakRegisterService.authorizationCallbacks (/home/h256/nest-project/node_modules/nestjs-keycloak/src/keycloakRegister.service.ts:127:15)
    at KeycloakRegisterService.defaultAuthorizationCallback (/home/h256/nest-project/node_modules/nestjs-keycloak/src/keycloakRegister.service.ts:107:12)
    at KeycloakRegisterService._callee$ (/home/h256/nest-project/node_modules/nestjs-keycloak/src/keycloakRegister.service.ts:279:12)
    at tryCatch (/home/h256/nest-project/node_modules/regenerator-runtime/runtime.js:63:40)
    at Generator.invoke [as _invoke] (/home/h256/nest-project/node_modules/regenerator-runtime/runtime.js:294:22)
    at Generator.next (/home/h256/nest-project/node_modules/regenerator-runtime/runtime.js:119:21)

Maybe it's helpful for reproducing - Complete dependencies:

 "dependencies": {
    "@nestjs/axios": "^0.0.1",
    "nestjs-axios-logger": "^0.0.3",
    "@nestjs/common": "^8.0.6",
    "@nestjs/config": "^1.0.1",
    "@nestjs/core": "^8.0.6",
    "@nestjs/platform-express": "^8.0.6",
    "@nestjs/schedule": "^1.0.1",
    "@nestjs/serve-static": "^2.2.2",
    "@nestjs/throttler": "^2.0.0",
    "app": "^0.1.0",
    "class-transformer": "^0.4.0",
    "csv-parse": "^4.16.0",
    "dotenv": "^10.0.0",
    "express-rate-limit": "^5.3.0",
    "fast-xml-parser": "^3.19.0",
    "get-port": "^5.1.1",
    "helmet": "^4.6.0",
    "keycloak-admin": "^1.14.22",
    "knex": "^0.21.21",
    "mmmagic": "^0.5.3",
    "nestjs-keycloak": "^2.1.3",
    "nestjs-keycloak-admin": "^1.5.19",
    "nestjs-objection": "^2.2.0",
    "objection": "^2.2.14",
    "pg": "^8.7.1",
    "reflect-metadata": "^0.1.13",
    "rimraf": "^3.0.2",
    "rxjs": "^7.3.0",
    "url-join": "^4.0.1",
    "uuid": "^8.3.2",
    "xml-sanitize-string": "^1.0.4"
  },
  "devDependencies": {
    "@nestjs/cli": "^8.1.1",
    "@nestjs/schematics": "^8.0.2",
    "@nestjs/testing": "^8.0.6",
    "@types/express": "^4.17.12",
    "@types/jest": "^26.0.23",
    "@types/node": "^14.17.1",
    "@types/supertest": "^2.0.11",
    "@types/uuid": "^8.3.0",
    "@typescript-eslint/eslint-plugin": "^4.15.2",
    "@typescript-eslint/parser": "^4.15.2",
    "eslint": "^7.20.0",
    "eslint-config-prettier": "^8.1.0",
    "eslint-plugin-prettier": "^3.3.1",
    "jest": "^26.6.3",
    "prettier": "^2.2.1",
    "supertest": "^6.1.3",
    "ts-jest": "^26.5.2",
    "ts-loader": "^8.0.17",
    "ts-node": "^9.1.1",
    "tsconfig-paths": "^3.9.0",
    "typescript": "^4.1.5",
    "webpack": "^5.28.0"
  },

If you can't reproduce I'm sure, that I'm doing something wrong :D