diff --git a/.eslintrc.json b/.eslintrc.json index c4a8de71b..0f6cbb07b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -6,7 +6,8 @@ "files": ["*.ts"], "parserOptions": { "project": ["tsconfig.json"], - "createDefaultProgram": true + "createDefaultProgram": true, + "tsconfigRootDir": "./" }, "extends": [ "plugin:@angular-eslint/recommended", @@ -21,7 +22,6 @@ "format": ["PascalCase"] } ], - "newline-before-return": "error", "max-len": "off", "no-useless-constructor": "off", "lines-between-class-members": ["error", "always"], @@ -36,12 +36,22 @@ "no-empty": ["error"], "@typescript-eslint/no-empty-function": ["error"], "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": ["error"], "@typescript-eslint/ban-types": ["error"], "no-useless-escape": ["error"], "no-prototype-builtins": ["error"], "prefer-spread": ["error"], - "@typescript-eslint/no-explicit-any": "off" + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/typedef": ["error"], + "@typescript-eslint/explicit-function-return-type": ["error"], + "newline-before-return": ["error"], + "@typescript-eslint/no-unused-vars": [ + "error", + { + "argsIgnorePattern": "^_", + "varsIgnorePattern": "^_", + "caughtErrorsIgnorePattern": "^_" + } + ] } }, { diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ed4324e53..62b0ad80b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,7 +27,7 @@ jobs: - name: Installing Dependencies run: npm ci - - name: Linting Frontend + - name: Linting Library run: npm run lint-lib - name: Testing Frontend diff --git a/.gitignore b/.gitignore index aa45d5da9..20529ac0d 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,4 @@ Thumbs.db debug.log /.husky +/.nx diff --git a/angular.json b/angular.json index 418fb2a2b..99239d49f 100644 --- a/angular.json +++ b/angular.json @@ -36,7 +36,10 @@ "lint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": ["projects/angular-auth-oidc-client/**/*.ts", "projects/angular-auth-oidc-client/**/*.html"] + "lintFilePatterns": [ + "projects/angular-auth-oidc-client/**/*.ts", + "projects/angular-auth-oidc-client/**/*.html" + ] } } } @@ -110,14 +113,14 @@ "sslKey": "certs/dev_localhost.key", "sslCert": "certs/dev_localhost.pem", "port": 4200, - "buildTarget": "sample-code-flow-multi-iframe:build" + "browserTarget": "sample-code-flow-multi-iframe:build" }, "configurations": { "production": { - "buildTarget": "sample-code-flow-multi-iframe:build:production" + "browserTarget": "sample-code-flow-multi-iframe:build:production" }, "development": { - "buildTarget": "sample-code-flow-multi-iframe:build:development" + "browserTarget": "sample-code-flow-multi-iframe:build:development" } }, "defaultConfiguration": "development" @@ -125,7 +128,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "buildTarget": "sample-code-flow-multi-iframe:build" + "browserTarget": "sample-code-flow-multi-iframe:build" } }, "test": { @@ -135,7 +138,10 @@ "polyfills": "projects/sample-code-flow-multi-iframe/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-multi-iframe/tsconfig.spec.json", "karmaConfig": "projects/sample-code-flow-multi-iframe/karma.conf.js", - "assets": ["projects/sample-code-flow-multi-iframe/src/favicon.ico", "projects/sample-code-flow-multi-iframe/src/assets"], + "assets": [ + "projects/sample-code-flow-multi-iframe/src/favicon.ico", + "projects/sample-code-flow-multi-iframe/src/assets" + ], "styles": ["projects/sample-code-flow-multi-iframe/src/styles.css"], "scripts": [] } @@ -143,7 +149,10 @@ "lint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": ["projects/sample-code-flow-multi-iframe/**/*.ts", "projects/sample-code-flow-multi-iframe/**/*.html"] + "lintFilePatterns": [ + "projects/sample-code-flow-multi-iframe/**/*.ts", + "projects/sample-code-flow-multi-iframe/**/*.html" + ] } } } @@ -216,14 +225,14 @@ "sslKey": "certs/dev_localhost.key", "sslCert": "certs/dev_localhost.pem", "port": 4204, - "buildTarget": "sample-code-flow-auto-login:build" + "browserTarget": "sample-code-flow-auto-login:build" }, "configurations": { "production": { - "buildTarget": "sample-code-flow-auto-login:build:production" + "browserTarget": "sample-code-flow-auto-login:build:production" }, "development": { - "buildTarget": "sample-code-flow-auto-login:build:development" + "browserTarget": "sample-code-flow-auto-login:build:development" } }, "defaultConfiguration": "development" @@ -231,7 +240,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "buildTarget": "sample-code-flow-auto-login:build" + "browserTarget": "sample-code-flow-auto-login:build" } }, "test": { @@ -241,7 +250,10 @@ "polyfills": "projects/sample-code-flow-auto-login/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-auto-login/tsconfig.spec.json", "karmaConfig": "projects/sample-code-flow-auto-login/karma.conf.js", - "assets": ["projects/sample-code-flow-auto-login/src/favicon.ico", "projects/sample-code-flow-auto-login/src/assets"], + "assets": [ + "projects/sample-code-flow-auto-login/src/favicon.ico", + "projects/sample-code-flow-auto-login/src/assets" + ], "styles": ["projects/sample-code-flow-auto-login/src/styles.css"], "scripts": [] } @@ -249,7 +261,10 @@ "lint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": ["projects/sample-code-flow-auto-login/**/*.ts", "projects/sample-code-flow-auto-login/**/*.html"] + "lintFilePatterns": [ + "projects/sample-code-flow-auto-login/**/*.ts", + "projects/sample-code-flow-auto-login/**/*.html" + ] } } } @@ -322,14 +337,14 @@ "sslKey": "certs/dev_localhost.key", "sslCert": "certs/dev_localhost.pem", "port": 4201, - "buildTarget": "sample-code-flow-http-config:build" + "browserTarget": "sample-code-flow-http-config:build" }, "configurations": { "production": { - "buildTarget": "sample-code-flow-http-config:build:production" + "browserTarget": "sample-code-flow-http-config:build:production" }, "development": { - "buildTarget": "sample-code-flow-http-config:build:development" + "browserTarget": "sample-code-flow-http-config:build:development" } }, "defaultConfiguration": "development" @@ -337,7 +352,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "buildTarget": "sample-code-flow-http-config:build" + "browserTarget": "sample-code-flow-http-config:build" } }, "test": { @@ -347,7 +362,10 @@ "polyfills": "projects/sample-code-flow-http-config/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-http-config/tsconfig.spec.json", "karmaConfig": "projects/sample-code-flow-http-config/karma.conf.js", - "assets": ["projects/sample-code-flow-http-config/src/favicon.ico", "projects/sample-code-flow-http-config/src/assets"], + "assets": [ + "projects/sample-code-flow-http-config/src/favicon.ico", + "projects/sample-code-flow-http-config/src/assets" + ], "styles": ["projects/sample-code-flow-http-config/src/styles.css"], "scripts": [] } @@ -355,7 +373,10 @@ "lint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": ["projects/sample-code-flow-http-config/**/*.ts", "projects/sample-code-flow-http-config/**/*.html"] + "lintFilePatterns": [ + "projects/sample-code-flow-http-config/**/*.ts", + "projects/sample-code-flow-http-config/**/*.html" + ] } } } @@ -376,7 +397,10 @@ "polyfills": "projects/sample-implicit-flow-google/src/polyfills.ts", "tsConfig": "projects/sample-implicit-flow-google/tsconfig.app.json", "aot": true, - "assets": ["projects/sample-implicit-flow-google/src/favicon.ico", "projects/sample-implicit-flow-google/src/assets"], + "assets": [ + "projects/sample-implicit-flow-google/src/favicon.ico", + "projects/sample-implicit-flow-google/src/assets" + ], "styles": ["projects/sample-implicit-flow-google/src/styles.css"], "scripts": [] }, @@ -424,14 +448,14 @@ "sslKey": "certs/dev_localhost.key", "sslCert": "certs/dev_localhost.pem", "port": 44386, - "buildTarget": "sample-implicit-flow-google:build" + "browserTarget": "sample-implicit-flow-google:build" }, "configurations": { "production": { - "buildTarget": "sample-implicit-flow-google:build:production" + "browserTarget": "sample-implicit-flow-google:build:production" }, "development": { - "buildTarget": "sample-implicit-flow-google:build:development" + "browserTarget": "sample-implicit-flow-google:build:development" } }, "defaultConfiguration": "development" @@ -439,7 +463,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "buildTarget": "sample-implicit-flow-google:build" + "browserTarget": "sample-implicit-flow-google:build" } }, "test": { @@ -449,7 +473,10 @@ "polyfills": "projects/sample-implicit-flow-google/src/polyfills.ts", "tsConfig": "projects/sample-implicit-flow-google/tsconfig.spec.json", "karmaConfig": "projects/sample-implicit-flow-google/karma.conf.js", - "assets": ["projects/sample-implicit-flow-google/src/favicon.ico", "projects/sample-implicit-flow-google/src/assets"], + "assets": [ + "projects/sample-implicit-flow-google/src/favicon.ico", + "projects/sample-implicit-flow-google/src/assets" + ], "styles": ["projects/sample-implicit-flow-google/src/styles.css"], "scripts": [] } @@ -457,7 +484,10 @@ "lint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": ["projects/sample-implicit-flow-google/**/*.ts", "projects/sample-implicit-flow-google/**/*.html"] + "lintFilePatterns": [ + "projects/sample-implicit-flow-google/**/*.ts", + "projects/sample-implicit-flow-google/**/*.html" + ] } } } @@ -530,14 +560,14 @@ "sslKey": "certs/dev_localhost.key", "sslCert": "certs/dev_localhost.pem", "port": 44347, - "buildTarget": "sample-code-flow-azuread:build" + "browserTarget": "sample-code-flow-azuread:build" }, "configurations": { "production": { - "buildTarget": "sample-code-flow-azuread:build:production" + "browserTarget": "sample-code-flow-azuread:build:production" }, "development": { - "buildTarget": "sample-code-flow-azuread:build:development" + "browserTarget": "sample-code-flow-azuread:build:development" } }, "defaultConfiguration": "development" @@ -545,7 +575,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "buildTarget": "sample-code-flow-azuread:build" + "browserTarget": "sample-code-flow-azuread:build" } }, "test": { @@ -567,7 +597,10 @@ "lint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": ["projects/sample-code-flow-azuread/**/*.ts", "projects/sample-code-flow-azuread/**/*.html"] + "lintFilePatterns": [ + "projects/sample-code-flow-azuread/**/*.ts", + "projects/sample-code-flow-azuread/**/*.html" + ] } } } @@ -640,14 +673,14 @@ "sslKey": "certs/dev_localhost.key", "sslCert": "certs/dev_localhost.pem", "port": 4200, - "buildTarget": "sample-code-flow-azure-b2c:build" + "browserTarget": "sample-code-flow-azure-b2c:build" }, "configurations": { "production": { - "buildTarget": "sample-code-flow-azure-b2c:build:production" + "browserTarget": "sample-code-flow-azure-b2c:build:production" }, "development": { - "buildTarget": "sample-code-flow-azure-b2c:build:development" + "browserTarget": "sample-code-flow-azure-b2c:build:development" } }, "defaultConfiguration": "development" @@ -655,7 +688,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "buildTarget": "sample-code-flow-azure-b2c:build" + "browserTarget": "sample-code-flow-azure-b2c:build" } }, "test": { @@ -665,7 +698,10 @@ "polyfills": "projects/sample-code-flow-azure-b2c/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-azure-b2c/tsconfig.spec.json", "karmaConfig": "projects/sample-code-flow-azure-b2c/karma.conf.js", - "assets": ["projects/sample-code-flow-azure-b2c/src/favicon.ico", "projects/sample-code-flow-azure-b2c/src/assets"], + "assets": [ + "projects/sample-code-flow-azure-b2c/src/favicon.ico", + "projects/sample-code-flow-azure-b2c/src/assets" + ], "styles": ["projects/sample-code-flow-azure-b2c/src/styles.css"], "scripts": [] } @@ -673,7 +709,10 @@ "lint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": ["projects/sample-code-flow-azure-b2c/**/*.ts", "projects/sample-code-flow-azure-b2c/**/*.html"] + "lintFilePatterns": [ + "projects/sample-code-flow-azure-b2c/**/*.ts", + "projects/sample-code-flow-azure-b2c/**/*.html" + ] } } } @@ -699,7 +738,9 @@ "projects/sample-implicit-flow-silent-renew/src/assets", "projects/sample-implicit-flow-silent-renew/src/silent-renew.html" ], - "styles": ["projects/sample-implicit-flow-silent-renew/src/styles.css"], + "styles": [ + "projects/sample-implicit-flow-silent-renew/src/styles.css" + ], "scripts": [] }, "configurations": { @@ -746,14 +787,14 @@ "sslKey": "certs/dev_localhost.key", "sslCert": "certs/dev_localhost.pem", "port": 4202, - "buildTarget": "sample-implicit-flow-silent-renew:build" + "browserTarget": "sample-implicit-flow-silent-renew:build" }, "configurations": { "production": { - "buildTarget": "sample-implicit-flow-silent-renew:build:production" + "browserTarget": "sample-implicit-flow-silent-renew:build:production" }, "development": { - "buildTarget": "sample-implicit-flow-silent-renew:build:development" + "browserTarget": "sample-implicit-flow-silent-renew:build:development" } }, "defaultConfiguration": "development" @@ -761,7 +802,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "buildTarget": "sample-implicit-flow-silent-renew:build" + "browserTarget": "sample-implicit-flow-silent-renew:build" } }, "test": { @@ -775,7 +816,9 @@ "projects/sample-implicit-flow-silent-renew/src/favicon.ico", "projects/sample-implicit-flow-silent-renew/src/assets" ], - "styles": ["projects/sample-implicit-flow-silent-renew/src/styles.css"], + "styles": [ + "projects/sample-implicit-flow-silent-renew/src/styles.css" + ], "scripts": [] } }, @@ -806,7 +849,10 @@ "polyfills": "projects/sample-code-flow-auth0/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-auth0/tsconfig.app.json", "aot": true, - "assets": ["projects/sample-code-flow-auth0/src/favicon.ico", "projects/sample-code-flow-auth0/src/assets"], + "assets": [ + "projects/sample-code-flow-auth0/src/favicon.ico", + "projects/sample-code-flow-auth0/src/assets" + ], "styles": ["projects/sample-code-flow-auth0/src/styles.css"], "scripts": [] }, @@ -854,14 +900,14 @@ "sslKey": "certs/dev_localhost.key", "sslCert": "certs/dev_localhost.pem", "port": 4210, - "buildTarget": "sample-code-flow-auth0:build" + "browserTarget": "sample-code-flow-auth0:build" }, "configurations": { "production": { - "buildTarget": "sample-code-flow-auth0:build:production" + "browserTarget": "sample-code-flow-auth0:build:production" }, "development": { - "buildTarget": "sample-code-flow-auth0:build:development" + "browserTarget": "sample-code-flow-auth0:build:development" } }, "defaultConfiguration": "development" @@ -869,7 +915,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "buildTarget": "sample-code-flow-auth0:build" + "browserTarget": "sample-code-flow-auth0:build" } }, "test": { @@ -879,7 +925,10 @@ "polyfills": "projects/sample-code-flow-auth0/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-auth0/tsconfig.spec.json", "karmaConfig": "projects/sample-code-flow-auth0/karma.conf.js", - "assets": ["projects/sample-code-flow-auth0/src/favicon.ico", "projects/sample-code-flow-auth0/src/assets"], + "assets": [ + "projects/sample-code-flow-auth0/src/favicon.ico", + "projects/sample-code-flow-auth0/src/assets" + ], "styles": ["projects/sample-code-flow-auth0/src/styles.css"], "scripts": [] } @@ -887,7 +936,10 @@ "lint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": ["projects/sample-code-flow-auth0/**/*.ts", "projects/sample-code-flow-auth0/**/*.html"] + "lintFilePatterns": [ + "projects/sample-code-flow-auth0/**/*.ts", + "projects/sample-code-flow-auth0/**/*.html" + ] } } } @@ -908,8 +960,13 @@ "polyfills": "projects/sample-code-flow-refresh-tokens/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-refresh-tokens/tsconfig.app.json", "aot": true, - "assets": ["projects/sample-code-flow-refresh-tokens/src/favicon.ico", "projects/sample-code-flow-refresh-tokens/src/assets"], - "styles": ["projects/sample-code-flow-refresh-tokens/src/styles.css"], + "assets": [ + "projects/sample-code-flow-refresh-tokens/src/favicon.ico", + "projects/sample-code-flow-refresh-tokens/src/assets" + ], + "styles": [ + "projects/sample-code-flow-refresh-tokens/src/styles.css" + ], "scripts": [] }, "configurations": { @@ -956,14 +1013,14 @@ "sslKey": "certs/dev_localhost.key", "sslCert": "certs/dev_localhost.pem", "port": 4204, - "buildTarget": "sample-code-flow-refresh-tokens:build" + "browserTarget": "sample-code-flow-refresh-tokens:build" }, "configurations": { "production": { - "buildTarget": "sample-code-flow-refresh-tokens:build:production" + "browserTarget": "sample-code-flow-refresh-tokens:build:production" }, "development": { - "buildTarget": "sample-code-flow-refresh-tokens:build:development" + "browserTarget": "sample-code-flow-refresh-tokens:build:development" } }, "defaultConfiguration": "development" @@ -971,7 +1028,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "buildTarget": "sample-code-flow-refresh-tokens:build" + "browserTarget": "sample-code-flow-refresh-tokens:build" } }, "test": { @@ -981,15 +1038,23 @@ "polyfills": "projects/sample-code-flow-refresh-tokens/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-refresh-tokens/tsconfig.spec.json", "karmaConfig": "projects/sample-code-flow-refresh-tokens/karma.conf.js", - "assets": ["projects/sample-code-flow-refresh-tokens/src/favicon.ico", "projects/sample-code-flow-refresh-tokens/src/assets"], - "styles": ["projects/sample-code-flow-refresh-tokens/src/styles.css"], + "assets": [ + "projects/sample-code-flow-refresh-tokens/src/favicon.ico", + "projects/sample-code-flow-refresh-tokens/src/assets" + ], + "styles": [ + "projects/sample-code-flow-refresh-tokens/src/styles.css" + ], "scripts": [] } }, "lint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": ["projects/sample-code-flow-refresh-tokens/**/*.ts", "projects/sample-code-flow-refresh-tokens/**/*.html"] + "lintFilePatterns": [ + "projects/sample-code-flow-refresh-tokens/**/*.ts", + "projects/sample-code-flow-refresh-tokens/**/*.html" + ] } } } @@ -1057,14 +1122,14 @@ "sslKey": "certs/dev_localhost.key", "sslCert": "certs/dev_localhost.pem", "port": 4204, - "buildTarget": "sample-code-flow-standalone:build" + "browserTarget": "sample-code-flow-standalone:build" }, "configurations": { "production": { - "buildTarget": "sample-code-flow-standalone:build:production" + "browserTarget": "sample-code-flow-standalone:build:production" }, "development": { - "buildTarget": "sample-code-flow-standalone:build:development" + "browserTarget": "sample-code-flow-standalone:build:development" } }, "defaultConfiguration": "development" @@ -1072,7 +1137,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "buildTarget": "sample-code-flow-standalone:build" + "browserTarget": "sample-code-flow-standalone:build" } }, "test": { @@ -1082,7 +1147,10 @@ "polyfills": ["zone.js", "zone.js/testing"], "tsConfig": "projects/sample-code-flow-standalone/tsconfig.spec.json", "karmaConfig": "projects/sample-code-flow-standalone/karma.conf.js", - "assets": ["projects/sample-code-flow-standalone/src/favicon.ico", "projects/sample-code-flow-standalone/src/assets"], + "assets": [ + "projects/sample-code-flow-standalone/src/favicon.ico", + "projects/sample-code-flow-standalone/src/assets" + ], "styles": ["projects/sample-code-flow-standalone/src/styles.css"], "scripts": [] } @@ -1090,7 +1158,10 @@ "lint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": ["projects/sample-code-flow-standalone/**/*.ts", "projects/sample-code-flow-standalone/**/*.html"] + "lintFilePatterns": [ + "projects/sample-code-flow-standalone/**/*.ts", + "projects/sample-code-flow-standalone/**/*.html" + ] } } } @@ -1111,8 +1182,13 @@ "polyfills": "projects/sample-code-flow-multi-Azure-B2C/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-multi-Azure-B2C/tsconfig.app.json", "aot": true, - "assets": ["projects/sample-code-flow-multi-Azure-B2C/src/favicon.ico", "projects/sample-code-flow-multi-Azure-B2C/src/assets"], - "styles": ["projects/sample-code-flow-multi-Azure-B2C/src/styles.css"], + "assets": [ + "projects/sample-code-flow-multi-Azure-B2C/src/favicon.ico", + "projects/sample-code-flow-multi-Azure-B2C/src/assets" + ], + "styles": [ + "projects/sample-code-flow-multi-Azure-B2C/src/styles.css" + ], "scripts": [] }, "configurations": { @@ -1159,14 +1235,14 @@ "sslKey": "certs/dev_localhost.key", "sslCert": "certs/dev_localhost.pem", "port": 4200, - "buildTarget": "sample-code-flow-multi-Azure-B2C:build" + "browserTarget": "sample-code-flow-multi-Azure-B2C:build" }, "configurations": { "production": { - "buildTarget": "sample-code-flow-multi-Azure-B2C:build:production" + "browserTarget": "sample-code-flow-multi-Azure-B2C:build:production" }, "development": { - "buildTarget": "sample-code-flow-multi-Azure-B2C:build:development" + "browserTarget": "sample-code-flow-multi-Azure-B2C:build:development" } }, "defaultConfiguration": "development" @@ -1174,7 +1250,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "buildTarget": "sample-code-flow-multi-Azure-B2C:build" + "browserTarget": "sample-code-flow-multi-Azure-B2C:build" } }, "test": { @@ -1184,15 +1260,23 @@ "polyfills": "projects/sample-code-flow-multi-Azure-B2C/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-multi-Azure-B2C/tsconfig.spec.json", "karmaConfig": "projects/sample-code-flow-multi-Azure-B2C/karma.conf.js", - "assets": ["projects/sample-code-flow-multi-Azure-B2C/src/favicon.ico", "projects/sample-code-flow-multi-Azure-B2C/src/assets"], - "styles": ["projects/sample-code-flow-multi-Azure-B2C/src/styles.css"], + "assets": [ + "projects/sample-code-flow-multi-Azure-B2C/src/favicon.ico", + "projects/sample-code-flow-multi-Azure-B2C/src/assets" + ], + "styles": [ + "projects/sample-code-flow-multi-Azure-B2C/src/styles.css" + ], "scripts": [] } }, "lint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": ["projects/sample-code-flow-multi-Azure-B2C/**/*.ts", "projects/sample-code-flow-multi-Azure-B2C/**/*.html"] + "lintFilePatterns": [ + "projects/sample-code-flow-multi-Azure-B2C/**/*.ts", + "projects/sample-code-flow-multi-Azure-B2C/**/*.html" + ] } } } @@ -1213,7 +1297,10 @@ "polyfills": "projects/sample-code-flow-multi-AAD/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-multi-AAD/tsconfig.app.json", "aot": true, - "assets": ["projects/sample-code-flow-multi-AAD/src/favicon.ico", "projects/sample-code-flow-multi-AAD/src/assets"], + "assets": [ + "projects/sample-code-flow-multi-AAD/src/favicon.ico", + "projects/sample-code-flow-multi-AAD/src/assets" + ], "styles": ["projects/sample-code-flow-multi-AAD/src/styles.css"], "scripts": [] }, @@ -1261,14 +1348,14 @@ "sslKey": "certs/dev_localhost.key", "sslCert": "certs/dev_localhost.pem", "port": 4200, - "buildTarget": "sample-code-flow-multi-AAD:build" + "browserTarget": "sample-code-flow-multi-AAD:build" }, "configurations": { "production": { - "buildTarget": "sample-code-flow-multi-AAD:build:production" + "browserTarget": "sample-code-flow-multi-AAD:build:production" }, "development": { - "buildTarget": "sample-code-flow-multi-AAD:build:development" + "browserTarget": "sample-code-flow-multi-AAD:build:development" } }, "defaultConfiguration": "development" @@ -1276,7 +1363,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "buildTarget": "sample-code-flow-multi-AAD:build" + "browserTarget": "sample-code-flow-multi-AAD:build" } }, "test": { @@ -1286,7 +1373,10 @@ "polyfills": "projects/sample-code-flow-multi-AAD/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-multi-AAD/tsconfig.spec.json", "karmaConfig": "projects/sample-code-flow-multi-AAD/karma.conf.js", - "assets": ["projects/sample-code-flow-multi-AAD/src/favicon.ico", "projects/sample-code-flow-multi-AAD/src/assets"], + "assets": [ + "projects/sample-code-flow-multi-AAD/src/favicon.ico", + "projects/sample-code-flow-multi-AAD/src/assets" + ], "styles": ["projects/sample-code-flow-multi-AAD/src/styles.css"], "scripts": [] } @@ -1294,7 +1384,10 @@ "lint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": ["projects/sample-code-flow-multi-AAD/**/*.ts", "projects/sample-code-flow-multi-AAD/**/*.html"] + "lintFilePatterns": [ + "projects/sample-code-flow-multi-AAD/**/*.ts", + "projects/sample-code-flow-multi-AAD/**/*.html" + ] } } } @@ -1319,7 +1412,9 @@ "projects/sample-code-flow-multi-Auth0-ID4-popup/src/favicon.ico", "projects/sample-code-flow-multi-Auth0-ID4-popup/src/assets" ], - "styles": ["projects/sample-code-flow-multi-Auth0-ID4-popup/src/styles.css"], + "styles": [ + "projects/sample-code-flow-multi-Auth0-ID4-popup/src/styles.css" + ], "scripts": [] }, "configurations": { @@ -1366,14 +1461,14 @@ "sslKey": "certs/dev_localhost.key", "sslCert": "certs/dev_localhost.pem", "port": 4204, - "buildTarget": "sample-code-flow-multi-Auth0-ID4-popup:build" + "browserTarget": "sample-code-flow-multi-Auth0-ID4-popup:build" }, "configurations": { "production": { - "buildTarget": "sample-code-flow-multi-Auth0-ID4-popup:build:production" + "browserTarget": "sample-code-flow-multi-Auth0-ID4-popup:build:production" }, "development": { - "buildTarget": "sample-code-flow-multi-Auth0-ID4-popup:build:development" + "browserTarget": "sample-code-flow-multi-Auth0-ID4-popup:build:development" } }, "defaultConfiguration": "development" @@ -1381,7 +1476,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "buildTarget": "sample-code-flow-multi-Auth0-ID4-popup:build" + "browserTarget": "sample-code-flow-multi-Auth0-ID4-popup:build" } }, "test": { @@ -1395,7 +1490,9 @@ "projects/sample-code-flow-multi-Auth0-ID4-popup/src/favicon.ico", "projects/sample-code-flow-multi-Auth0-ID4-popup/src/assets" ], - "styles": ["projects/sample-code-flow-multi-Auth0-ID4-popup/src/styles.css"], + "styles": [ + "projects/sample-code-flow-multi-Auth0-ID4-popup/src/styles.css" + ], "scripts": [] } }, @@ -1426,8 +1523,13 @@ "polyfills": "projects/sample-code-flow-multi-Auth0-ID4/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-multi-Auth0-ID4/tsconfig.app.json", "aot": true, - "assets": ["projects/sample-code-flow-multi-Auth0-ID4/src/favicon.ico", "projects/sample-code-flow-multi-Auth0-ID4/src/assets"], - "styles": ["projects/sample-code-flow-multi-Auth0-ID4/src/styles.css"], + "assets": [ + "projects/sample-code-flow-multi-Auth0-ID4/src/favicon.ico", + "projects/sample-code-flow-multi-Auth0-ID4/src/assets" + ], + "styles": [ + "projects/sample-code-flow-multi-Auth0-ID4/src/styles.css" + ], "scripts": [] }, "configurations": { @@ -1474,14 +1576,14 @@ "sslKey": "certs/dev_localhost.key", "sslCert": "certs/dev_localhost.pem", "port": 4204, - "buildTarget": "sample-code-flow-multi-Auth0-ID4:build" + "browserTarget": "sample-code-flow-multi-Auth0-ID4:build" }, "configurations": { "production": { - "buildTarget": "sample-code-flow-multi-Auth0-ID4:build:production" + "browserTarget": "sample-code-flow-multi-Auth0-ID4:build:production" }, "development": { - "buildTarget": "sample-code-flow-multi-Auth0-ID4:build:development" + "browserTarget": "sample-code-flow-multi-Auth0-ID4:build:development" } }, "defaultConfiguration": "development" @@ -1489,7 +1591,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "buildTarget": "sample-code-flow-multi-Auth0-ID4:build" + "browserTarget": "sample-code-flow-multi-Auth0-ID4:build" } }, "test": { @@ -1499,15 +1601,23 @@ "polyfills": "projects/sample-code-flow-multi-Auth0-ID4/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-multi-Auth0-ID4/tsconfig.spec.json", "karmaConfig": "projects/sample-code-flow-multi-Auth0-ID4/karma.conf.js", - "assets": ["projects/sample-code-flow-multi-Auth0-ID4/src/favicon.ico", "projects/sample-code-flow-multi-Auth0-ID4/src/assets"], - "styles": ["projects/sample-code-flow-multi-Auth0-ID4/src/styles.css"], + "assets": [ + "projects/sample-code-flow-multi-Auth0-ID4/src/favicon.ico", + "projects/sample-code-flow-multi-Auth0-ID4/src/assets" + ], + "styles": [ + "projects/sample-code-flow-multi-Auth0-ID4/src/styles.css" + ], "scripts": [] } }, "lint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": ["projects/sample-code-flow-multi-Auth0-ID4/**/*.ts", "projects/sample-code-flow-multi-Auth0-ID4/**/*.html"] + "lintFilePatterns": [ + "projects/sample-code-flow-multi-Auth0-ID4/**/*.ts", + "projects/sample-code-flow-multi-Auth0-ID4/**/*.html" + ] } } } @@ -1528,7 +1638,10 @@ "polyfills": "projects/sample-code-flow-lazy-loaded/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-lazy-loaded/tsconfig.app.json", "aot": true, - "assets": ["projects/sample-code-flow-lazy-loaded/src/favicon.ico", "projects/sample-code-flow-lazy-loaded/src/assets"], + "assets": [ + "projects/sample-code-flow-lazy-loaded/src/favicon.ico", + "projects/sample-code-flow-lazy-loaded/src/assets" + ], "styles": ["projects/sample-code-flow-lazy-loaded/src/styles.css"], "scripts": [] }, @@ -1575,14 +1688,14 @@ "options": { "sslKey": "certs/dev_localhost.key", "sslCert": "certs/dev_localhost.pem", - "buildTarget": "sample-code-flow-lazy-loaded:build" + "browserTarget": "sample-code-flow-lazy-loaded:build" }, "configurations": { "production": { - "buildTarget": "sample-code-flow-lazy-loaded:build:production" + "browserTarget": "sample-code-flow-lazy-loaded:build:production" }, "development": { - "buildTarget": "sample-code-flow-lazy-loaded:build:development" + "browserTarget": "sample-code-flow-lazy-loaded:build:development" } }, "defaultConfiguration": "development" @@ -1590,7 +1703,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "buildTarget": "sample-code-flow-lazy-loaded:build" + "browserTarget": "sample-code-flow-lazy-loaded:build" } }, "test": { @@ -1600,7 +1713,10 @@ "polyfills": "projects/sample-code-flow-lazy-loaded/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-lazy-loaded/tsconfig.spec.json", "karmaConfig": "projects/sample-code-flow-lazy-loaded/karma.conf.js", - "assets": ["projects/sample-code-flow-lazy-loaded/src/favicon.ico", "projects/sample-code-flow-lazy-loaded/src/assets"], + "assets": [ + "projects/sample-code-flow-lazy-loaded/src/favicon.ico", + "projects/sample-code-flow-lazy-loaded/src/assets" + ], "styles": ["projects/sample-code-flow-lazy-loaded/src/styles.css"], "scripts": [] } @@ -1608,7 +1724,10 @@ "lint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": ["projects/sample-code-flow-lazy-loaded/**/*.ts", "projects/sample-code-flow-lazy-loaded/**/*.html"] + "lintFilePatterns": [ + "projects/sample-code-flow-lazy-loaded/**/*.ts", + "projects/sample-code-flow-lazy-loaded/**/*.html" + ] } } } @@ -1629,7 +1748,10 @@ "polyfills": "projects/sample-code-flow-popup/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-popup/tsconfig.app.json", "aot": true, - "assets": ["projects/sample-code-flow-popup/src/favicon.ico", "projects/sample-code-flow-popup/src/assets"], + "assets": [ + "projects/sample-code-flow-popup/src/favicon.ico", + "projects/sample-code-flow-popup/src/assets" + ], "styles": ["projects/sample-code-flow-popup/src/styles.css"], "scripts": [] }, @@ -1677,14 +1799,14 @@ "sslKey": "certs/dev_localhost.key", "sslCert": "certs/dev_localhost.pem", "port": 4204, - "buildTarget": "sample-code-flow-popup:build" + "browserTarget": "sample-code-flow-popup:build" }, "configurations": { "production": { - "buildTarget": "sample-code-flow-popup:build:production" + "browserTarget": "sample-code-flow-popup:build:production" }, "development": { - "buildTarget": "sample-code-flow-popup:build:development" + "browserTarget": "sample-code-flow-popup:build:development" } }, "defaultConfiguration": "development" @@ -1692,7 +1814,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "buildTarget": "sample-code-flow-popup:build" + "browserTarget": "sample-code-flow-popup:build" } }, "test": { @@ -1702,7 +1824,10 @@ "polyfills": "projects/sample-code-flow-popup/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-popup/tsconfig.spec.json", "karmaConfig": "projects/sample-code-flow-popup/karma.conf.js", - "assets": ["projects/sample-code-flow-popup/src/favicon.ico", "projects/sample-code-flow-popup/src/assets"], + "assets": [ + "projects/sample-code-flow-popup/src/favicon.ico", + "projects/sample-code-flow-popup/src/assets" + ], "styles": ["projects/sample-code-flow-popup/src/styles.css"], "scripts": [] } @@ -1777,14 +1902,14 @@ "sslKey": "certs/dev_localhost.key", "sslCert": "certs/dev_localhost.pem", "port": 4207, - "buildTarget": "sample-code-flow-par:build" + "browserTarget": "sample-code-flow-par:build" }, "configurations": { "production": { - "buildTarget": "sample-code-flow-par:build:production" + "browserTarget": "sample-code-flow-par:build:production" }, "development": { - "buildTarget": "sample-code-flow-par:build:development" + "browserTarget": "sample-code-flow-par:build:development" } }, "defaultConfiguration": "development" @@ -1792,7 +1917,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "buildTarget": "sample-code-flow-par:build" + "browserTarget": "sample-code-flow-par:build" } }, "test": { @@ -1802,7 +1927,10 @@ "polyfills": "projects/sample-code-flow-par/src/polyfills.ts", "tsConfig": "projects/sample-code-flow-par/tsconfig.spec.json", "karmaConfig": "projects/sample-code-flow-par/karma.conf.js", - "assets": ["projects/sample-code-flow-par/src/favicon.ico", "projects/sample-code-flow-par/src/assets"], + "assets": [ + "projects/sample-code-flow-par/src/favicon.ico", + "projects/sample-code-flow-par/src/assets" + ], "styles": ["projects/sample-code-flow-par/src/styles.css"], "scripts": [] } @@ -1833,7 +1961,9 @@ "projects/sample-code-flow-auto-login-all-routes/src/assets", "projects/sample-code-flow-auto-login-all-routes/src/silent-renew.html" ], - "styles": ["projects/sample-code-flow-auto-login-all-routes/src/styles.css"], + "styles": [ + "projects/sample-code-flow-auto-login-all-routes/src/styles.css" + ], "scripts": [] }, "configurations": { @@ -1875,14 +2005,14 @@ "sslKey": "certs/dev_localhost.key", "sslCert": "certs/dev_localhost.pem", "port": 4204, - "buildTarget": "sample-code-flow-auto-login-all-routes:build" + "browserTarget": "sample-code-flow-auto-login-all-routes:build" }, "configurations": { "production": { - "buildTarget": "sample-code-flow-auto-login-all-routes:build:production" + "browserTarget": "sample-code-flow-auto-login-all-routes:build:production" }, "development": { - "buildTarget": "sample-code-flow-auto-login-all-routes:build:development" + "browserTarget": "sample-code-flow-auto-login-all-routes:build:development" } }, "defaultConfiguration": "development" @@ -1890,7 +2020,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "buildTarget": "sample-code-flow-auto-login-all-routes:build" + "browserTarget": "sample-code-flow-auto-login-all-routes:build" } }, "test": { @@ -1904,7 +2034,9 @@ "projects/sample-code-flow-auto-login-all-routes/src/favicon.ico", "projects/sample-code-flow-auto-login-all-routes/src/assets" ], - "styles": ["projects/sample-code-flow-auto-login-all-routes/src/styles.css"], + "styles": [ + "projects/sample-code-flow-auto-login-all-routes/src/styles.css" + ], "scripts": [] } } diff --git a/lefthook.yml b/lefthook.yml index e70b39d18..cfcc9684c 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -10,9 +10,13 @@ pre-push: run: npm run fix-prettier {staged_files} pre-commit: + parallel: true commands: check-blockwords: run: npm run check-blockwords + + lint: + run: npm run lint-lib # # pre-commit: # parallel: true diff --git a/projects/angular-auth-oidc-client/.eslintrc.json b/projects/angular-auth-oidc-client/.eslintrc.json index bace0286d..c39ff084c 100644 --- a/projects/angular-auth-oidc-client/.eslintrc.json +++ b/projects/angular-auth-oidc-client/.eslintrc.json @@ -28,17 +28,6 @@ "style": "camelCase" } ], - "@typescript-eslint/typedef": ["error"], - "@typescript-eslint/explicit-function-return-type": ["error"], - "newline-before-return": ["error"], - "@typescript-eslint/no-unused-vars": [ - "error", - { - "argsIgnorePattern": "^_", - "varsIgnorePattern": "^_", - "caughtErrorsIgnorePattern": "^_" - } - ], "no-restricted-imports": [ "error", { diff --git a/projects/angular-auth-oidc-client/src/lib/api/data.service.ts b/projects/angular-auth-oidc-client/src/lib/api/data.service.ts index b16ca2264..31a93b916 100644 --- a/projects/angular-auth-oidc-client/src/lib/api/data.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/api/data.service.ts @@ -1,5 +1,5 @@ import { HttpHeaders, HttpParams } from '@angular/common/http'; -import { Injectable } from '@angular/core'; +import { Injectable, inject } from '@angular/core'; import { Observable } from 'rxjs'; import { OpenIdConfiguration } from '../config/openid-configuration'; import { HttpBaseService } from './http-base.service'; @@ -8,7 +8,7 @@ const NGSW_CUSTOM_PARAM = 'ngsw-bypass'; @Injectable({ providedIn: 'root' }) export class DataService { - constructor(private readonly httpClient: HttpBaseService) {} + private readonly httpClient = inject(HttpBaseService); get( url: string, @@ -25,7 +25,7 @@ export class DataService { } post( - url: string, + url: string | null, body: any, config: OpenIdConfiguration, headersParams?: HttpHeaders @@ -33,7 +33,7 @@ export class DataService { const headers = headersParams || this.prepareHeaders(); const params = this.prepareParams(config); - return this.httpClient.post(url, body, { headers, params }); + return this.httpClient.post(url ?? '', body, { headers, params }); } private prepareHeaders(token?: string): HttpHeaders { diff --git a/projects/angular-auth-oidc-client/src/lib/api/http-base.service.ts b/projects/angular-auth-oidc-client/src/lib/api/http-base.service.ts index 77dc4382a..5116101de 100644 --- a/projects/angular-auth-oidc-client/src/lib/api/http-base.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/api/http-base.service.ts @@ -1,10 +1,10 @@ import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; +import { Injectable, inject } from '@angular/core'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class HttpBaseService { - constructor(private readonly http: HttpClient) {} + private readonly http = inject(HttpClient); get(url: string, params?: { [key: string]: any }): Observable { return this.http.get(url, params); diff --git a/projects/angular-auth-oidc-client/src/lib/auth-config.spec.ts b/projects/angular-auth-oidc-client/src/lib/auth-config.spec.ts new file mode 100644 index 000000000..c1e706da9 --- /dev/null +++ b/projects/angular-auth-oidc-client/src/lib/auth-config.spec.ts @@ -0,0 +1,17 @@ +import { PassedInitialConfig, createStaticLoader } from './auth-config'; + +describe('AuthConfig', () => { + describe('createStaticLoader', () => { + it('should throw an error if no config is provided', () => { + // Arrange + const passedConfig = {} as PassedInitialConfig; + + // Act + + // Assert + expect(() => createStaticLoader(passedConfig)).toThrowError( + 'No config provided!' + ); + }); + }); +}); diff --git a/projects/angular-auth-oidc-client/src/lib/auth-config.ts b/projects/angular-auth-oidc-client/src/lib/auth-config.ts index a1226cb2c..2bebe22bc 100644 --- a/projects/angular-auth-oidc-client/src/lib/auth-config.ts +++ b/projects/angular-auth-oidc-client/src/lib/auth-config.ts @@ -13,6 +13,10 @@ export interface PassedInitialConfig { export function createStaticLoader( passedConfig: PassedInitialConfig ): StsConfigLoader { + if (!passedConfig?.config) { + throw new Error('No config provided!'); + } + return new StsConfigStaticLoader(passedConfig.config); } diff --git a/projects/angular-auth-oidc-client/src/lib/auth-state/auth-state.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/auth-state/auth-state.service.spec.ts index 135031d46..7f1f239ae 100644 --- a/projects/angular-auth-oidc-client/src/lib/auth-state/auth-state.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/auth-state/auth-state.service.spec.ts @@ -1,12 +1,13 @@ import { TestBed } from '@angular/core/testing'; import { Observable } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { LoggerService } from '../logging/logger.service'; import { EventTypes } from '../public-events/event-types'; import { PublicEventsService } from '../public-events/public-events.service'; import { StoragePersistenceService } from '../storage/storage-persistence.service'; import { PlatformProvider } from '../utils/platform-provider/platform.provider'; import { TokenValidationService } from '../validation/token-validation.service'; +import { ValidationResult } from '../validation/validation-result'; import { AuthStateService } from './auth-state.service'; describe('Auth State Service', () => { @@ -20,16 +21,10 @@ describe('Auth State Service', () => { providers: [ AuthStateService, PublicEventsService, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { - provide: TokenValidationService, - useClass: mockClass(TokenValidationService), - }, - { provide: PlatformProvider, useClass: mockClass(PlatformProvider) }, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, + mockProvider(LoggerService), + mockProvider(TokenValidationService), + mockProvider(PlatformProvider), + mockProvider(StoragePersistenceService), ], }); }); @@ -95,13 +90,13 @@ describe('Auth State Service', () => { .withArgs(allConfigs[0]) .and.returnValue('someAccessToken') .withArgs(allConfigs[1]) - .and.returnValue(null); + .and.returnValue(''); spyOn(storagePersistenceService, 'getIdToken') .withArgs(allConfigs[0]) .and.returnValue('someIdToken') .withArgs(allConfigs[1]) - .and.returnValue(null); + .and.returnValue(''); const spy = spyOn( (authStateService as any).authenticatedInternal$, @@ -175,13 +170,13 @@ describe('Auth State Service', () => { .withArgs({ configId: 'configId1' }) .and.returnValue('someAccessToken') .withArgs({ configId: 'configId2' }) - .and.returnValue(null); + .and.returnValue(''); spyOn(storagePersistenceService, 'getIdToken') .withArgs({ configId: 'configId1' }) .and.returnValue('someIdToken') .withArgs({ configId: 'configId2' }) - .and.returnValue(null); + .and.returnValue(''); const spy = spyOn( (authStateService as any).authenticatedInternal$, @@ -210,7 +205,7 @@ describe('Auth State Service', () => { authStateService.updateAndPublishAuthState({ isAuthenticated: false, isRenewProcess: false, - validationResult: null, + validationResult: {} as ValidationResult, }); expect(eventsService.fireEvent).toHaveBeenCalledOnceWith( @@ -297,7 +292,7 @@ describe('Auth State Service', () => { spyOn(storagePersistenceService, 'getIdToken').and.returnValue(''); const result = authStateService.getAccessToken({ configId: 'configId1' }); - expect(result).toBe(null); + expect(result).toBe(''); }); it('returns false if storagePersistenceService returns something falsy but authorized', () => { @@ -328,7 +323,7 @@ describe('Auth State Service', () => { spyOn(storagePersistenceService, 'getAuthenticationResult') .withArgs({ configId: 'configId1' }) - .and.returnValue(null); + .and.returnValue({}); const result = authStateService.getAuthenticationResult({ configId: 'configId1', @@ -341,13 +336,13 @@ describe('Auth State Service', () => { spyOn(authStateService, 'isAuthenticated').and.returnValue(true); spyOn(storagePersistenceService, 'getAuthenticationResult') .withArgs({ configId: 'configId1' }) - .and.returnValue(null); + .and.returnValue({}); const result = authStateService.getAuthenticationResult({ configId: 'configId1', }); - expect(result).toBe(null); + expect(result).toEqual({}); }); it('isAuthorized is true returns object', () => { @@ -365,7 +360,7 @@ describe('Auth State Service', () => { configId: 'configId1', }); - expect(result.scope).toBe('HenloFuriend'); + expect(result?.scope).toBe('HenloFuriend'); }); }); @@ -375,7 +370,7 @@ describe('Auth State Service', () => { spyOn(storagePersistenceService, 'getIdToken').and.returnValue(''); const result = authStateService.getIdToken({ configId: 'configId1' }); - expect(result).toBe(null); + expect(result).toBe(''); }); it('isAuthorized is true returns decodeURIComponent(token)', () => { @@ -399,7 +394,7 @@ describe('Auth State Service', () => { configId: 'configId1', }); - expect(result).toBe(null); + expect(result).toBe(''); }); it('isAuthorized is true returns decodeURIComponent(token)', () => { diff --git a/projects/angular-auth-oidc-client/src/lib/auth-state/auth-state.service.ts b/projects/angular-auth-oidc-client/src/lib/auth-state/auth-state.service.ts index a5f4200be..86c3f46e1 100644 --- a/projects/angular-auth-oidc-client/src/lib/auth-state/auth-state.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/auth-state/auth-state.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { BehaviorSubject, Observable } from 'rxjs'; +import { BehaviorSubject, Observable, throwError } from 'rxjs'; import { distinctUntilChanged } from 'rxjs/operators'; import { OpenIdConfiguration } from '../config/openid-configuration'; import { AuthResult } from '../flows/callback-context'; @@ -60,7 +60,7 @@ export class AuthStateService { setAuthorizationData( accessToken: string, - authResult: AuthResult, + authResult: AuthResult | null, currentConfig: OpenIdConfiguration, allConfigs: OpenIdConfiguration[] ): void { @@ -78,9 +78,13 @@ export class AuthStateService { this.setAuthenticatedAndFireEvent(allConfigs); } - getAccessToken(configuration: OpenIdConfiguration): string { + getAccessToken(configuration: OpenIdConfiguration | null): string { + if (!configuration) { + return ''; + } + if (!this.isAuthenticated(configuration)) { - return null; + return ''; } const token = this.storagePersistenceService.getAccessToken(configuration); @@ -88,9 +92,13 @@ export class AuthStateService { return this.decodeURIComponentSafely(token); } - getIdToken(configuration: OpenIdConfiguration): string { + getIdToken(configuration: OpenIdConfiguration | null): string { + if (!configuration) { + return ''; + } + if (!this.isAuthenticated(configuration)) { - return null; + return ''; } const token = this.storagePersistenceService.getIdToken(configuration); @@ -98,9 +106,13 @@ export class AuthStateService { return this.decodeURIComponentSafely(token); } - getRefreshToken(configuration: OpenIdConfiguration): string { + getRefreshToken(configuration: OpenIdConfiguration | null): string { + if (!configuration) { + return ''; + } + if (!this.isAuthenticated(configuration)) { - return null; + return ''; } const token = this.storagePersistenceService.getRefreshToken(configuration); @@ -108,7 +120,13 @@ export class AuthStateService { return this.decodeURIComponentSafely(token); } - getAuthenticationResult(configuration: OpenIdConfiguration): AuthResult { + getAuthenticationResult( + configuration: OpenIdConfiguration | null + ): AuthResult | null { + if (!configuration) { + return null; + } + if (!this.isAuthenticated(configuration)) { return null; } @@ -118,7 +136,13 @@ export class AuthStateService { ); } - areAuthStorageTokensValid(configuration: OpenIdConfiguration): boolean { + areAuthStorageTokensValid( + configuration: OpenIdConfiguration | null + ): boolean { + if (!configuration) { + return false; + } + if (!this.isAuthenticated(configuration)) { return false; } @@ -207,7 +231,18 @@ export class AuthStateService { return hasExpired; } - isAuthenticated(configuration: OpenIdConfiguration): boolean { + isAuthenticated(configuration: OpenIdConfiguration | null): boolean { + if (!configuration) { + throwError( + () => + new Error( + 'Please provide a configuration before setting up the module' + ) + ); + + return false; + } + const hasAccessToken = !!this.storagePersistenceService.getAccessToken(configuration); const hasIdToken = @@ -225,7 +260,7 @@ export class AuthStateService { } private persistAccessTokenExpirationTime( - authResult: AuthResult, + authResult: AuthResult | null, configuration: OpenIdConfiguration ): void { if (authResult?.expires_in) { @@ -249,7 +284,9 @@ export class AuthStateService { return { isAuthenticated: true, - allConfigsAuthenticated: [{ configId, isAuthenticated: true }], + allConfigsAuthenticated: [ + { configId: configId ?? '', isAuthenticated: true }, + ], }; } @@ -264,7 +301,9 @@ export class AuthStateService { return { isAuthenticated: false, - allConfigsAuthenticated: [{ configId, isAuthenticated: false }], + allConfigsAuthenticated: [ + { configId: configId ?? '', isAuthenticated: false }, + ], }; } @@ -275,7 +314,7 @@ export class AuthStateService { allConfigs: OpenIdConfiguration[] ): AuthenticatedResult { const allConfigsAuthenticated = allConfigs.map((config) => ({ - configId: config.configId, + configId: config.configId ?? '', isAuthenticated: this.isAuthenticated(config), })); diff --git a/projects/angular-auth-oidc-client/src/lib/auth-state/check-auth.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/auth-state/check-auth.service.spec.ts index 4ac26f36e..df28d48ca 100644 --- a/projects/angular-auth-oidc-client/src/lib/auth-state/check-auth.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/auth-state/check-auth.service.spec.ts @@ -1,7 +1,7 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { of, throwError } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockAbstractProvider, mockProvider } from '../../test/auto-mock'; import { AutoLoginService } from '../auto-login/auto-login.service'; import { CallbackService } from '../callback/callback.service'; import { PeriodicallyTokenCheckService } from '../callback/periodically-token-check.service'; @@ -10,9 +10,12 @@ import { StsConfigLoader, StsConfigStaticLoader, } from '../config/loader/config-loader'; +import { OpenIdConfiguration } from '../config/openid-configuration'; +import { CallbackContext } from '../flows/callback-context'; import { CheckSessionService } from '../iframe/check-session.service'; import { SilentRenewService } from '../iframe/silent-renew.service'; import { LoggerService } from '../logging/logger.service'; +import { LoginResponse } from '../login/login-response'; import { PopUpService } from '../login/popup/popup.service'; import { EventTypes } from '../public-events/event-types'; import { PublicEventsService } from '../public-events/public-events.service'; @@ -41,45 +44,20 @@ describe('CheckAuthService', () => { TestBed.configureTestingModule({ imports: [RouterTestingModule], providers: [ - { - provide: CheckSessionService, - useClass: mockClass(CheckSessionService), - }, - { - provide: SilentRenewService, - useClass: mockClass(SilentRenewService), - }, - { provide: UserService, useClass: mockClass(UserService) }, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { provide: AuthStateService, useClass: mockClass(AuthStateService) }, - { provide: CallbackService, useClass: mockClass(CallbackService) }, - { - provide: RefreshSessionService, - useClass: mockClass(RefreshSessionService), - }, - { - provide: PeriodicallyTokenCheckService, - useClass: mockClass(PeriodicallyTokenCheckService), - }, - { provide: PopUpService, useClass: mockClass(PopUpService) }, - { - provide: StsConfigLoader, - useClass: mockClass(StsConfigStaticLoader), - }, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, + mockProvider(CheckSessionService), + mockProvider(SilentRenewService), + mockProvider(UserService), + mockProvider(LoggerService), + mockProvider(AuthStateService), + mockProvider(CallbackService), + mockProvider(RefreshSessionService), + mockProvider(PeriodicallyTokenCheckService), + mockProvider(PopUpService), + mockProvider(CurrentUrlService), + mockProvider(PublicEventsService), + mockAbstractProvider(StsConfigLoader, StsConfigStaticLoader), AutoLoginService, - CheckAuthService, - { - provide: CurrentUrlService, - useClass: mockClass(CurrentUrlService), - }, - { - provide: PublicEventsService, - useClass: mockClass(PublicEventsService), - }, + mockProvider(StoragePersistenceService), ], }); }); @@ -103,7 +81,7 @@ describe('CheckAuthService', () => { }); afterEach(() => { - storagePersistenceService.clear(null); + storagePersistenceService.clear({} as OpenIdConfiguration); }); it('should create', () => { @@ -181,24 +159,6 @@ describe('CheckAuthService', () => { }); })); - it('returns isAuthenticated: false with error message when config is not valid', waitForAsync(() => { - const allConfigs = []; - - checkAuthService - .checkAuth(allConfigs[0], allConfigs) - .subscribe((result) => - expect(result).toEqual({ - isAuthenticated: false, - errorMessage: - 'Please provide at least one configuration before setting up the module', - configId: null, - idToken: '', - userData: null, - accessToken: '', - }) - ); - })); - it('returns null and sendMessageToMainWindow if currently in a popup', waitForAsync(() => { const allConfigs = [ { configId: 'configId1', authority: 'some-authority' }, @@ -207,6 +167,9 @@ describe('CheckAuthService', () => { spyOn(popUpService as any, 'canAccessSessionStorage').and.returnValue( true ); + spyOn(currentUrlService, 'getCurrentUrl').and.returnValue( + 'http://localhost:4200' + ); spyOnProperty(popUpService as any, 'windowInternal').and.returnValue({ opener: {} as Window, }); @@ -224,6 +187,7 @@ describe('CheckAuthService', () => { userData: null, idToken: '', accessToken: '', + configId: '', }); expect(popupSpy).toHaveBeenCalled(); }); @@ -238,11 +202,16 @@ describe('CheckAuthService', () => { spyOn(authStateService, 'areAuthStorageTokensValid').and.returnValue( true ); + const spy = spyOn( callBackService, 'handleCallbackAndFireEvents' ).and.returnValue(throwError(() => new Error('ERROR'))); + spyOn(currentUrlService, 'getCurrentUrl').and.returnValue( + 'http://localhost:4200' + ); + checkAuthService .checkAuth(allConfigs[0], allConfigs) .subscribe((result) => { @@ -267,10 +236,16 @@ describe('CheckAuthService', () => { spyOn(authStateService, 'areAuthStorageTokensValid').and.returnValue( true ); + spyOn(currentUrlService, 'getCurrentUrl').and.returnValue( + 'http://localhost:4200' + ); + spyOn(authStateService, 'getAccessToken').and.returnValue('at'); + spyOn(authStateService, 'getIdToken').and.returnValue('idt'); + const spy = spyOn( callBackService, 'handleCallbackAndFireEvents' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); checkAuthService .checkAuth(allConfigs[0], allConfigs) @@ -278,9 +253,9 @@ describe('CheckAuthService', () => { expect(result).toEqual({ isAuthenticated: true, userData: undefined, - accessToken: undefined, + accessToken: 'at', configId: 'configId1', - idToken: undefined, + idToken: 'idt', }); expect(spy).toHaveBeenCalled(); }); @@ -295,10 +270,17 @@ describe('CheckAuthService', () => { spyOn(authStateService, 'areAuthStorageTokensValid').and.returnValue( true ); + const spy = spyOn( callBackService, 'handleCallbackAndFireEvents' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); + + spyOn(currentUrlService, 'getCurrentUrl').and.returnValue( + 'http://localhost:4200' + ); + spyOn(authStateService, 'getAccessToken').and.returnValue('at'); + spyOn(authStateService, 'getIdToken').and.returnValue('idt'); checkAuthService .checkAuth(allConfigs[0], allConfigs) @@ -306,9 +288,9 @@ describe('CheckAuthService', () => { expect(result).toEqual({ isAuthenticated: true, userData: undefined, - accessToken: undefined, + accessToken: 'at', configId: 'configId1', - idToken: undefined, + idToken: 'idt', }); expect(spy).not.toHaveBeenCalled(); }); @@ -323,9 +305,17 @@ describe('CheckAuthService', () => { spyOn(authStateService, 'areAuthStorageTokensValid').and.returnValue( true ); + spyOn(currentUrlService, 'getCurrentUrl').and.returnValue( + 'http://localhost:4200' + ); spyOn(callBackService, 'handleCallbackAndFireEvents').and.returnValue( - of(null) + of({} as CallbackContext) ); + spyOn(userService, 'getUserDataFromStore').and.returnValue({ + some: 'user-data', + }); + spyOn(authStateService, 'getAccessToken').and.returnValue('at'); + spyOn(authStateService, 'getIdToken').and.returnValue('idt'); const setAuthorizedAndFireEventSpy = spyOn( authStateService, @@ -338,10 +328,12 @@ describe('CheckAuthService', () => { .subscribe((result) => { expect(result).toEqual({ isAuthenticated: true, - userData: undefined, - accessToken: undefined, + userData: { + some: 'user-data', + }, + accessToken: 'at', configId: 'configId1', - idToken: undefined, + idToken: 'idt', }); expect(setAuthorizedAndFireEventSpy).toHaveBeenCalled(); expect(userServiceSpy).toHaveBeenCalled(); @@ -357,8 +349,13 @@ describe('CheckAuthService', () => { spyOn(authStateService, 'areAuthStorageTokensValid').and.returnValue( false ); + spyOn(authStateService, 'getAccessToken').and.returnValue('at'); + spyOn(authStateService, 'getIdToken').and.returnValue('it'); spyOn(callBackService, 'handleCallbackAndFireEvents').and.returnValue( - of(null) + of({} as CallbackContext) + ); + spyOn(currentUrlService, 'getCurrentUrl').and.returnValue( + 'http://localhost:4200' ); const setAuthorizedAndFireEventSpy = spyOn( @@ -373,9 +370,9 @@ describe('CheckAuthService', () => { expect(result).toEqual({ isAuthenticated: false, userData: undefined, - accessToken: undefined, + accessToken: 'at', configId: 'configId1', - idToken: undefined, + idToken: 'it', }); expect(setAuthorizedAndFireEventSpy).not.toHaveBeenCalled(); expect(userServiceSpy).not.toHaveBeenCalled(); @@ -387,8 +384,13 @@ describe('CheckAuthService', () => { { configId: 'configId1', authority: 'some-authority' }, ]; + spyOn(currentUrlService, 'getCurrentUrl').and.returnValue( + 'http://localhost:4200' + ); + spyOn(authStateService, 'getAccessToken').and.returnValue('at'); + spyOn(authStateService, 'getIdToken').and.returnValue('idt'); spyOn(callBackService, 'handleCallbackAndFireEvents').and.returnValue( - of(null) + of({} as CallbackContext) ); spyOn(authStateService, 'areAuthStorageTokensValid').and.returnValue( true @@ -400,9 +402,9 @@ describe('CheckAuthService', () => { expect(result).toEqual({ isAuthenticated: true, userData: undefined, - accessToken: undefined, + accessToken: 'at', configId: 'configId1', - idToken: undefined, + idToken: 'idt', }); }); })); @@ -412,9 +414,10 @@ describe('CheckAuthService', () => { { configId: 'configId1', authority: 'some-authority' }, ]; - spyOn(callBackService, 'handleCallbackAndFireEvents').and.returnValue( - of(null) + spyOn(currentUrlService, 'getCurrentUrl').and.returnValue( + 'http://localhost:4200' ); + spyOn(callBackService, 'isCallback').and.returnValue(false); spyOn(authStateService, 'areAuthStorageTokensValid').and.returnValue( true ); @@ -431,8 +434,11 @@ describe('CheckAuthService', () => { { configId: 'configId1', authority: 'some-authority' }, ]; + spyOn(currentUrlService, 'getCurrentUrl').and.returnValue( + 'http://localhost:4200' + ); spyOn(callBackService, 'handleCallbackAndFireEvents').and.returnValue( - of(null) + of({} as CallbackContext) ); spyOn(authStateService, 'areAuthStorageTokensValid').and.returnValue( true @@ -453,12 +459,14 @@ describe('CheckAuthService', () => { const allConfigs = [config]; spyOn(callBackService, 'handleCallbackAndFireEvents').and.returnValue( - of(null) + of({} as CallbackContext) ); spyOn(authStateService, 'areAuthStorageTokensValid').and.returnValue( true ); - + spyOn(currentUrlService, 'getCurrentUrl').and.returnValue( + 'http://localhost:4200' + ); const spy = spyOn( periodicallyTokenCheckService, 'startTokenValidationPeriodically' @@ -475,7 +483,10 @@ describe('CheckAuthService', () => { ]; spyOn(callBackService, 'handleCallbackAndFireEvents').and.returnValue( - of(null) + of({} as CallbackContext) + ); + spyOn(currentUrlService, 'getCurrentUrl').and.returnValue( + 'http://localhost:4200' ); spyOn(authStateService, 'areAuthStorageTokensValid').and.returnValue( true @@ -496,7 +507,10 @@ describe('CheckAuthService', () => { ]; spyOn(callBackService, 'handleCallbackAndFireEvents').and.returnValue( - of(null) + of({} as CallbackContext) + ); + spyOn(currentUrlService, 'getCurrentUrl').and.returnValue( + 'http://localhost:4200' ); spyOn(authStateService, 'areAuthStorageTokensValid').and.returnValue( true @@ -516,8 +530,11 @@ describe('CheckAuthService', () => { { configId: 'configId1', authority: 'some-authority' }, ]; + spyOn(currentUrlService, 'getCurrentUrl').and.returnValue( + 'http://localhost:4200' + ); spyOn(callBackService, 'handleCallbackAndFireEvents').and.returnValue( - of(null) + of({} as CallbackContext) ); spyOn(authStateService, 'areAuthStorageTokensValid').and.returnValue( true @@ -536,7 +553,7 @@ describe('CheckAuthService', () => { ]; spyOn(callBackService, 'handleCallbackAndFireEvents').and.returnValue( - of(null) + of({} as CallbackContext) ); spyOn(authStateService, 'areAuthStorageTokensValid').and.returnValue( false @@ -552,6 +569,14 @@ describe('CheckAuthService', () => { const allConfigs = [ { configId: 'configId1', authority: 'some-authority' }, ]; + + spyOn(currentUrlService, 'getCurrentUrl').and.returnValue( + 'http://localhost:4200' + ); + spyOn(authStateService, 'areAuthStorageTokensValid').and.returnValue( + true + ); + const fireEventSpy = spyOn(publicEventsService, 'fireEvent'); checkAuthService.checkAuth(allConfigs[0], allConfigs).subscribe(() => { @@ -572,6 +597,9 @@ describe('CheckAuthService', () => { spyOn(callBackService, 'handleCallbackAndFireEvents').and.returnValue( throwError(() => new Error('ERROR')) ); + spyOn(currentUrlService, 'getCurrentUrl').and.returnValue( + 'http://localhost:4200' + ); checkAuthService.checkAuth(allConfigs[0], allConfigs).subscribe(() => { expect(fireEventSpy.calls.allArgs()).toEqual([ @@ -589,11 +617,14 @@ describe('CheckAuthService', () => { ]; spyOn(callBackService, 'handleCallbackAndFireEvents').and.returnValue( - of(null) + of({} as CallbackContext) ); spyOn(authStateService, 'areAuthStorageTokensValid').and.returnValue( true ); + spyOn(refreshSessionService, 'forceRefreshSession').and.returnValue( + of({ isAuthenticated: true } as LoginResponse) + ); spyOn(silentRenewService, 'isSilentRenewConfigured').and.returnValue( true @@ -617,7 +648,7 @@ describe('CheckAuthService', () => { false ); spyOn(callBackService, 'handleCallbackAndFireEvents').and.returnValue( - of(null) + of({} as CallbackContext) ); spyOn(refreshSessionService, 'forceRefreshSession').and.returnValue( @@ -647,7 +678,7 @@ describe('CheckAuthService', () => { false ); spyOn(callBackService, 'handleCallbackAndFireEvents').and.returnValue( - of(null) + of({} as CallbackContext) ); spyOn(checkSessionService, 'isCheckSessionConfigured').and.returnValue( true @@ -697,7 +728,7 @@ describe('CheckAuthService', () => { false ); spyOn(callBackService, 'handleCallbackAndFireEvents').and.returnValue( - of(null) + of({} as CallbackContext) ); spyOn(checkSessionService, 'isCheckSessionConfigured').and.returnValue( true @@ -840,7 +871,7 @@ describe('CheckAuthService', () => { 'the-state-param' ); - const allConfigs = []; + const allConfigs: OpenIdConfiguration[] = []; checkAuthService.checkAuthMultiple(allConfigs).subscribe({ error: (error) => { diff --git a/projects/angular-auth-oidc-client/src/lib/auth-state/check-auth.service.ts b/projects/angular-auth-oidc-client/src/lib/auth-state/check-auth.service.ts index e37635494..2a93cb56d 100644 --- a/projects/angular-auth-oidc-client/src/lib/auth-state/check-auth.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/auth-state/check-auth.service.ts @@ -36,30 +36,45 @@ export class CheckAuthService { private readonly publicEventsService: PublicEventsService ) {} - checkAuth( + private getConfig( configuration: OpenIdConfiguration, + url: string | undefined + ): OpenIdConfiguration | null { + const stateParamFromUrl = + this.currentUrlService.getStateParamFromCurrentUrl(url); + + return Boolean(stateParamFromUrl) + ? this.getConfigurationWithUrlState([configuration], stateParamFromUrl) + : configuration; + } + + checkAuth( + configuration: OpenIdConfiguration | null, allConfigs: OpenIdConfiguration[], url?: string ): Observable { + if (!configuration) { + return throwError( + () => + new Error( + 'Please provide a configuration before setting up the module' + ) + ); + } + this.publicEventsService.fireEvent(EventTypes.CheckingAuth); const stateParamFromUrl = this.currentUrlService.getStateParamFromCurrentUrl(url); + const config = this.getConfig(configuration, url); - if (!!stateParamFromUrl) { - configuration = this.getConfigurationWithUrlState( - [configuration], - stateParamFromUrl + if (!config) { + return throwError( + () => + new Error( + `could not find matching config for state ${stateParamFromUrl}` + ) ); - - if (!configuration) { - return throwError( - () => - new Error( - `could not find matching config for state ${stateParamFromUrl}` - ) - ); - } } return this.checkAuthWithConfig(configuration, allConfigs, url); @@ -99,9 +114,18 @@ export class CheckAuthService { } checkAuthIncludingServer( - configuration: OpenIdConfiguration, + configuration: OpenIdConfiguration | null, allConfigs: OpenIdConfiguration[] ): Observable { + if (!configuration) { + return throwError( + () => + new Error( + 'Please provide a configuration before setting up the module' + ) + ); + } + return this.checkAuthWithConfig(configuration, allConfigs).pipe( switchMap((loginResponse) => { const { isAuthenticated } = loginResponse; @@ -134,42 +158,64 @@ export class CheckAuthService { this.loggerService.logError(config, errorMessage); - return of({ + const result: LoginResponse = { isAuthenticated: false, errorMessage, userData: null, idToken: '', accessToken: '', - configId: null, - }); + configId: '', + }; + + return of(result); } const currentUrl = url || this.currentUrlService.getCurrentUrl(); + + if (!currentUrl) { + const errorMessage = 'No URL found!'; + + this.loggerService.logError(config, errorMessage); + + const result: LoginResponse = { + isAuthenticated: false, + errorMessage, + userData: null, + idToken: '', + accessToken: '', + configId: '', + }; + + return of(result); + } + const { configId, authority } = config; this.loggerService.logDebug( config, - `Working with config '${configId}' using ${authority}` + `Working with config '${configId}' using '${authority}'` ); if (this.popupService.isCurrentlyInPopup(config)) { - this.popupService.sendMessageToMainWindow(currentUrl); + this.popupService.sendMessageToMainWindow(currentUrl, config); - return of({ + const result: LoginResponse = { isAuthenticated: false, errorMessage: '', userData: null, idToken: '', accessToken: '', - }); + configId: '', + }; + + return of(result); } const isCallback = this.callbackService.isCallback(currentUrl); this.loggerService.logDebug( config, - 'currentUrl to check auth with: ', - currentUrl + `currentUrl to check auth with: '${currentUrl}'` ); const callback$ = isCallback @@ -178,13 +224,18 @@ export class CheckAuthService { config, allConfigs ) - : of(null); + : of({}); return callback$.pipe( map(() => { const isAuthenticated = this.authStateService.areAuthStorageTokensValid(config); + this.loggerService.logDebug( + config, + `checkAuth completed. Firing events now. isAuthenticated: ${isAuthenticated}` + ); + if (isAuthenticated) { this.startCheckSessionAndValidation(config, allConfigs); @@ -192,25 +243,21 @@ export class CheckAuthService { this.authStateService.setAuthenticatedAndFireEvent(allConfigs); this.userService.publishUserDataIfExists(config, allConfigs); } - } - this.loggerService.logDebug( - config, - 'checkAuth completed - firing events now. isAuthenticated: ' + - isAuthenticated - ); + this.publicEventsService.fireEvent(EventTypes.CheckingAuthFinished); + } - return { + const result: LoginResponse = { isAuthenticated, userData: this.userService.getUserDataFromStore(config), accessToken: this.authStateService.getAccessToken(config), idToken: this.authStateService.getIdToken(config), configId, }; + + return result; }), tap(({ isAuthenticated }) => { - this.publicEventsService.fireEvent(EventTypes.CheckingAuthFinished); - if (isAuthenticated) { this.autoLoginService.checkSavedRedirectRouteAndNavigate(config); } @@ -222,14 +269,16 @@ export class CheckAuthService { message ); - return of({ + const result: LoginResponse = { isAuthenticated: false, errorMessage: message, userData: null, idToken: '', accessToken: '', configId, - }); + }; + + return of(result); }) ); } @@ -254,8 +303,12 @@ export class CheckAuthService { private getConfigurationWithUrlState( configurations: OpenIdConfiguration[], - stateFromUrl: string + stateFromUrl: string | null ): OpenIdConfiguration | null { + if (!stateFromUrl) { + return null; + } + for (const config of configurations) { const storedState = this.storagePersistenceService.read( 'authStateControl', diff --git a/projects/angular-auth-oidc-client/src/lib/auth.module.spec.ts b/projects/angular-auth-oidc-client/src/lib/auth.module.spec.ts index b49a148a5..9327ba198 100644 --- a/projects/angular-auth-oidc-client/src/lib/auth.module.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/auth.module.spec.ts @@ -1,6 +1,6 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { of } from 'rxjs'; -import { mockClass } from '../test/auto-mock'; +import { mockProvider } from '../test/auto-mock'; import { PASSED_CONFIG } from './auth-config'; import { AuthModule } from './auth.module'; import { ConfigurationService } from './config/config.service'; @@ -17,18 +17,13 @@ describe('AuthModule', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [AuthModule.forRoot({ config: { authority: 'something' } })], - providers: [ - { - provide: ConfigurationService, - useClass: mockClass(ConfigurationService), - }, - ], + providers: [mockProvider(ConfigurationService)], }).compileComponents(); })); it('should create', () => { expect(AuthModule).toBeDefined(); - expect(AuthModule.forRoot(null)).toBeDefined(); + expect(AuthModule.forRoot({})).toBeDefined(); }); it('should provide config', () => { @@ -50,16 +45,11 @@ describe('AuthModule', () => { AuthModule.forRoot({ loader: { provide: StsConfigLoader, - useFactory: () => new StsConfigHttpLoader(of(null)), + useFactory: () => new StsConfigHttpLoader(of({})), }, }), ], - providers: [ - { - provide: ConfigurationService, - useClass: mockClass(ConfigurationService), - }, - ], + providers: [mockProvider(ConfigurationService)], }).compileComponents(); })); diff --git a/projects/angular-auth-oidc-client/src/lib/auto-login/auto-login-all-routes.guard.spec.ts b/projects/angular-auth-oidc-client/src/lib/auto-login/auto-login-all-routes.guard.spec.ts index 5eff3a736..0bdb75db9 100644 --- a/projects/angular-auth-oidc-client/src/lib/auto-login/auto-login-all-routes.guard.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/auto-login/auto-login-all-routes.guard.spec.ts @@ -1,8 +1,12 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; -import { Router, RouterStateSnapshot } from '@angular/router'; +import { + ActivatedRouteSnapshot, + Router, + RouterStateSnapshot, +} from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { Observable, of } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { CheckAuthService } from '../auth-state/check-auth.service'; import { ConfigurationService } from '../config/config.service'; import { LoginResponse } from '../login/login-response'; @@ -17,22 +21,10 @@ describe(`AutoLoginAllRoutesGuard`, () => { imports: [RouterTestingModule], providers: [ AutoLoginService, - { - provide: CheckAuthService, - useClass: mockClass(CheckAuthService), - }, - { - provide: LoginService, - useClass: mockClass(LoginService), - }, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, - { - provide: ConfigurationService, - useClass: mockClass(ConfigurationService), - }, + mockProvider(CheckAuthService), + mockProvider(LoginService), + mockProvider(StoragePersistenceService), + mockProvider(ConfigurationService), ], }); }); @@ -62,7 +54,7 @@ describe(`AutoLoginAllRoutesGuard`, () => { }); afterEach(() => { - storagePersistenceService.clear(null); + storagePersistenceService.clear({}); }); it('should create', () => { @@ -84,9 +76,12 @@ describe(`AutoLoginAllRoutesGuard`, () => { ); const loginSpy = spyOn(loginService, 'login'); - const canActivate$ = guard.canActivate(null, { - url: 'some-url1', - } as RouterStateSnapshot) as Observable; + const canActivate$ = guard.canActivate( + {} as ActivatedRouteSnapshot, + { + url: 'some-url1', + } as RouterStateSnapshot + ) as Observable; canActivate$.subscribe(() => { expect(saveRedirectRouteSpy).toHaveBeenCalledOnceWith( @@ -111,9 +106,12 @@ describe(`AutoLoginAllRoutesGuard`, () => { 'saveRedirectRoute' ); const loginSpy = spyOn(loginService, 'login'); - const canActivate$ = guard.canActivate(null, { - url: 'some-url1', - } as RouterStateSnapshot) as Observable; + const canActivate$ = guard.canActivate( + {} as ActivatedRouteSnapshot, + { + url: 'some-url1', + } as RouterStateSnapshot + ) as Observable; canActivate$.subscribe(() => { expect(saveRedirectRouteSpy).not.toHaveBeenCalled(); @@ -139,9 +137,12 @@ describe(`AutoLoginAllRoutesGuard`, () => { 'saveRedirectRoute' ); const loginSpy = spyOn(loginService, 'login'); - const canActivate$ = guard.canActivate(null, { - url: 'some-url1', - } as RouterStateSnapshot) as Observable; + const canActivate$ = guard.canActivate( + {} as ActivatedRouteSnapshot, + { + url: 'some-url1', + } as RouterStateSnapshot + ) as Observable; canActivate$.subscribe(() => { expect(saveRedirectRouteSpy).not.toHaveBeenCalled(); @@ -167,9 +168,12 @@ describe(`AutoLoginAllRoutesGuard`, () => { 'saveRedirectRoute' ); const loginSpy = spyOn(loginService, 'login'); - const canActivateChild$ = guard.canActivateChild(null, { - url: 'some-url1', - } as RouterStateSnapshot) as Observable; + const canActivateChild$ = guard.canActivateChild( + {} as ActivatedRouteSnapshot, + { + url: 'some-url1', + } as RouterStateSnapshot + ) as Observable; canActivateChild$.subscribe(() => { expect(saveRedirectRouteSpy).toHaveBeenCalledOnceWith( @@ -194,9 +198,12 @@ describe(`AutoLoginAllRoutesGuard`, () => { 'saveRedirectRoute' ); const loginSpy = spyOn(loginService, 'login'); - const canActivateChild$ = guard.canActivateChild(null, { - url: 'some-url1', - } as RouterStateSnapshot) as Observable; + const canActivateChild$ = guard.canActivateChild( + {} as ActivatedRouteSnapshot, + { + url: 'some-url1', + } as RouterStateSnapshot + ) as Observable; canActivateChild$.subscribe(() => { expect(saveRedirectRouteSpy).not.toHaveBeenCalled(); @@ -222,9 +229,12 @@ describe(`AutoLoginAllRoutesGuard`, () => { 'saveRedirectRoute' ); const loginSpy = spyOn(loginService, 'login'); - const canActivateChild$ = guard.canActivateChild(null, { - url: 'some-url1', - } as RouterStateSnapshot) as Observable; + const canActivateChild$ = guard.canActivateChild( + {} as ActivatedRouteSnapshot, + { + url: 'some-url1', + } as RouterStateSnapshot + ) as Observable; canActivateChild$.subscribe(() => { expect(saveRedirectRouteSpy).not.toHaveBeenCalled(); diff --git a/projects/angular-auth-oidc-client/src/lib/auto-login/auto-login-partial-routes.guard.spec.ts b/projects/angular-auth-oidc-client/src/lib/auto-login/auto-login-partial-routes.guard.spec.ts index 1225b8f70..8dce28319 100644 --- a/projects/angular-auth-oidc-client/src/lib/auto-login/auto-login-partial-routes.guard.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/auto-login/auto-login-partial-routes.guard.spec.ts @@ -6,7 +6,7 @@ import { } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { AuthStateService } from '../auth-state/auth-state.service'; import { CheckAuthService } from '../auth-state/check-auth.service'; import { ConfigurationService } from '../config/config.service'; @@ -24,23 +24,11 @@ describe(`AutoLoginPartialRoutesGuard`, () => { imports: [RouterTestingModule], providers: [ AutoLoginService, - { provide: AuthStateService, useClass: mockClass(AuthStateService) }, - { - provide: LoginService, - useClass: mockClass(LoginService), - }, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, - { - provide: CheckAuthService, - useClass: mockClass(CheckAuthService), - }, - { - provide: ConfigurationService, - useClass: mockClass(ConfigurationService), - }, + mockProvider(AuthStateService), + mockProvider(LoginService), + mockProvider(StoragePersistenceService), + mockProvider(CheckAuthService), + mockProvider(ConfigurationService), ], }); }); @@ -70,7 +58,7 @@ describe(`AutoLoginPartialRoutesGuard`, () => { }); afterEach(() => { - storagePersistenceService.clear(null); + storagePersistenceService.clear({}); }); it('should create', () => { @@ -93,7 +81,10 @@ describe(`AutoLoginPartialRoutesGuard`, () => { const loginSpy = spyOn(loginService, 'login'); guard - .canActivate(null, { url: 'some-url1' } as RouterStateSnapshot) + .canActivate( + {} as ActivatedRouteSnapshot, + { url: 'some-url1' } as RouterStateSnapshot + ) .subscribe(() => { expect(saveRedirectRouteSpy).toHaveBeenCalledOnceWith( { configId: 'configId1' }, @@ -157,7 +148,10 @@ describe(`AutoLoginPartialRoutesGuard`, () => { const loginSpy = spyOn(loginService, 'login'); guard - .canActivate(null, { url: 'some-url1' } as RouterStateSnapshot) + .canActivate( + {} as ActivatedRouteSnapshot, + { url: 'some-url1' } as RouterStateSnapshot + ) .subscribe(() => { expect(saveRedirectRouteSpy).not.toHaveBeenCalled(); expect(loginSpy).not.toHaveBeenCalled(); @@ -184,7 +178,10 @@ describe(`AutoLoginPartialRoutesGuard`, () => { const loginSpy = spyOn(loginService, 'login'); guard - .canActivateChild(null, { url: 'some-url1' } as RouterStateSnapshot) + .canActivateChild( + {} as ActivatedRouteSnapshot, + { url: 'some-url1' } as RouterStateSnapshot + ) .subscribe(() => { expect(saveRedirectRouteSpy).toHaveBeenCalledOnceWith( { configId: 'configId1' }, @@ -248,7 +245,10 @@ describe(`AutoLoginPartialRoutesGuard`, () => { const loginSpy = spyOn(loginService, 'login'); guard - .canActivateChild(null, { url: 'some-url1' } as RouterStateSnapshot) + .canActivateChild( + {} as ActivatedRouteSnapshot, + { url: 'some-url1' } as RouterStateSnapshot + ) .subscribe(() => { expect(saveRedirectRouteSpy).not.toHaveBeenCalled(); expect(loginSpy).not.toHaveBeenCalled(); @@ -368,7 +368,7 @@ describe(`AutoLoginPartialRoutesGuard`, () => { }); afterEach(() => { - storagePersistenceService.clear(null); + storagePersistenceService.clear({}); }); it('should save current route (empty) and call `login` if not authenticated already', waitForAsync(() => { diff --git a/projects/angular-auth-oidc-client/src/lib/auto-login/auto-login.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/auto-login/auto-login.service.spec.ts index 33c1780b3..b0f685aea 100644 --- a/projects/angular-auth-oidc-client/src/lib/auto-login/auto-login.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/auto-login/auto-login.service.spec.ts @@ -1,7 +1,7 @@ import { TestBed } from '@angular/core/testing'; import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { StoragePersistenceService } from '../storage/storage-persistence.service'; import { AutoLoginService } from './auto-login.service'; @@ -13,13 +13,7 @@ describe('AutoLoginService ', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [RouterTestingModule], - providers: [ - AutoLoginService, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, - ], + providers: [AutoLoginService, mockProvider(StoragePersistenceService)], }); }); diff --git a/projects/angular-auth-oidc-client/src/lib/auto-login/auto-login.service.ts b/projects/angular-auth-oidc-client/src/lib/auto-login/auto-login.service.ts index 7092e74df..0ed139f53 100644 --- a/projects/angular-auth-oidc-client/src/lib/auto-login/auto-login.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/auto-login/auto-login.service.ts @@ -12,7 +12,10 @@ export class AutoLoginService { private readonly router: Router ) {} - checkSavedRedirectRouteAndNavigate(config: OpenIdConfiguration): void { + checkSavedRedirectRouteAndNavigate(config: OpenIdConfiguration | null): void { + if (!config) { + return; + } const savedRouteForRedirect = this.getStoredRedirectRoute(config); if (savedRouteForRedirect != null) { @@ -27,7 +30,11 @@ export class AutoLoginService { * @param config The OpenId configuration. * @param url The redirect URL to save. */ - saveRedirectRoute(config: OpenIdConfiguration, url: string): void { + saveRedirectRoute(config: OpenIdConfiguration | null, url: string): void { + if (!config) { + return; + } + this.storageService.write(STORAGE_KEY, url, config); } diff --git a/projects/angular-auth-oidc-client/src/lib/callback/callback.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/callback/callback.service.spec.ts index 198eed333..93490ac75 100644 --- a/projects/angular-auth-oidc-client/src/lib/callback/callback.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/callback/callback.service.spec.ts @@ -1,6 +1,7 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { Observable, of } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; +import { CallbackContext } from '../flows/callback-context'; import { FlowHelper } from '../utils/flowHelper/flow-helper.service'; import { UrlService } from '../utils/url/url.service'; import { CallbackService } from './callback.service'; @@ -19,16 +20,10 @@ describe('CallbackService ', () => { imports: [], providers: [ CallbackService, - { provide: UrlService, useClass: mockClass(UrlService) }, + mockProvider(UrlService), FlowHelper, - { - provide: ImplicitFlowCallbackService, - useClass: mockClass(ImplicitFlowCallbackService), - }, - { - provide: CodeFlowCallbackService, - useClass: mockClass(CodeFlowCallbackService), - }, + mockProvider(ImplicitFlowCallbackService), + mockProvider(CodeFlowCallbackService), ], }); }); @@ -62,7 +57,7 @@ describe('CallbackService ', () => { const authorizedCallbackWithCodeSpy = spyOn( codeFlowCallbackService, 'authenticatedCallbackWithCode' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); callbackService .handleCallbackAndFireEvents('anyUrl', { configId: 'configId1' }, [ @@ -83,7 +78,7 @@ describe('CallbackService ', () => { const authorizedCallbackWithCodeSpy = spyOn( implicitFlowCallbackService, 'authenticatedImplicitFlowCallback' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); callbackService .handleCallbackAndFireEvents('anyUrl', { configId: 'configId1' }, [ @@ -103,7 +98,7 @@ describe('CallbackService ', () => { const authorizedCallbackWithCodeSpy = spyOn( implicitFlowCallbackService, 'authenticatedImplicitFlowCallback' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); callbackService .handleCallbackAndFireEvents( @@ -130,7 +125,7 @@ describe('CallbackService ', () => { const authenticatedCallbackWithCodeSpy = spyOn( codeFlowCallbackService, 'authenticatedCallbackWithCode' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); callbackService .handleCallbackAndFireEvents('anyUrl', { configId: 'configId1' }, [ diff --git a/projects/angular-auth-oidc-client/src/lib/callback/callback.service.ts b/projects/angular-auth-oidc-client/src/lib/callback/callback.service.ts index 41d9c4f5a..5f90d7b80 100644 --- a/projects/angular-auth-oidc-client/src/lib/callback/callback.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/callback/callback.service.ts @@ -12,7 +12,7 @@ import { ImplicitFlowCallbackService } from './implicit-flow-callback.service'; export class CallbackService { private readonly stsCallbackInternal$ = new Subject(); - get stsCallback$(): Observable { + get stsCallback$(): Observable { return this.stsCallbackInternal$.asObservable(); } @@ -24,6 +24,10 @@ export class CallbackService { ) {} isCallback(currentUrl: string): boolean { + if (!currentUrl) { + return false; + } + return this.urlService.isCallbackFromSts(currentUrl); } @@ -32,7 +36,7 @@ export class CallbackService { config: OpenIdConfiguration, allConfigs: OpenIdConfiguration[] ): Observable { - let callback$: Observable; + let callback$: Observable = new Observable(); if (this.flowHelper.isCurrentFlowCodeFlow(config)) { callback$ = this.codeFlowCallbackService.authenticatedCallbackWithCode( diff --git a/projects/angular-auth-oidc-client/src/lib/callback/code-flow-callback.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/callback/code-flow-callback.service.spec.ts index a7acdfc5e..3e9996c4a 100644 --- a/projects/angular-auth-oidc-client/src/lib/callback/code-flow-callback.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/callback/code-flow-callback.service.spec.ts @@ -2,7 +2,8 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of, throwError } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; +import { CallbackContext } from '../flows/callback-context'; import { FlowsDataService } from '../flows/flows-data.service'; import { FlowsService } from '../flows/flows.service'; import { CodeFlowCallbackService } from './code-flow-callback.service'; @@ -20,9 +21,9 @@ describe('CodeFlowCallbackService ', () => { imports: [RouterTestingModule], providers: [ CodeFlowCallbackService, - { provide: FlowsService, useClass: mockClass(FlowsService) }, - { provide: FlowsDataService, useClass: mockClass(FlowsDataService) }, - IntervalService, + mockProvider(FlowsService), + mockProvider(FlowsDataService), + mockProvider(IntervalService), ], }); }); @@ -44,7 +45,7 @@ describe('CodeFlowCallbackService ', () => { const spy = spyOn( flowsService, 'processCodeFlowCallback' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); //spyOn(configurationProvider, 'getOpenIDConfiguration').and.returnValue({ triggerAuthorizationResultEvent: true }); const config = { diff --git a/projects/angular-auth-oidc-client/src/lib/callback/code-flow-callback.service.ts b/projects/angular-auth-oidc-client/src/lib/callback/code-flow-callback.service.ts index 9ffa3ec66..a1f2dca6f 100644 --- a/projects/angular-auth-oidc-client/src/lib/callback/code-flow-callback.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/callback/code-flow-callback.service.ts @@ -23,11 +23,10 @@ export class CodeFlowCallbackService { allConfigs: OpenIdConfiguration[] ): Observable { const isRenewProcess = this.flowsDataService.isSilentRenewRunning(config); - const { - triggerAuthorizationResultEvent, - postLoginRoute, - unauthorizedRoute, - } = config; + const { triggerAuthorizationResultEvent } = config; + + const postLoginRoute = config.postLoginRoute || '/'; + const unauthorizedRoute = config.unauthorizedRoute || '/'; return this.flowsService .processCodeFlowCallback(urlToCheck, config, allConfigs) diff --git a/projects/angular-auth-oidc-client/src/lib/callback/implicit-flow-callback.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/callback/implicit-flow-callback.service.spec.ts index 9e924284a..830de5e55 100644 --- a/projects/angular-auth-oidc-client/src/lib/callback/implicit-flow-callback.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/callback/implicit-flow-callback.service.spec.ts @@ -2,7 +2,8 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of, throwError } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; +import { CallbackContext } from '../flows/callback-context'; import { FlowsDataService } from '../flows/flows-data.service'; import { FlowsService } from '../flows/flows.service'; import { ImplicitFlowCallbackService } from './implicit-flow-callback.service'; @@ -19,10 +20,9 @@ describe('ImplicitFlowCallbackService ', () => { TestBed.configureTestingModule({ imports: [RouterTestingModule], providers: [ - ImplicitFlowCallbackService, - { provide: FlowsService, useClass: mockClass(FlowsService) }, - { provide: FlowsDataService, useClass: mockClass(FlowsDataService) }, - IntervalService, + mockProvider(FlowsService), + mockProvider(FlowsDataService), + mockProvider(IntervalService), ], }); }); @@ -44,7 +44,7 @@ describe('ImplicitFlowCallbackService ', () => { const spy = spyOn( flowsService, 'processImplicitFlowCallback' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const config = { configId: 'configId1', triggerAuthorizationResultEvent: true, diff --git a/projects/angular-auth-oidc-client/src/lib/callback/implicit-flow-callback.service.ts b/projects/angular-auth-oidc-client/src/lib/callback/implicit-flow-callback.service.ts index c2ac2250e..d7a03828d 100644 --- a/projects/angular-auth-oidc-client/src/lib/callback/implicit-flow-callback.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/callback/implicit-flow-callback.service.ts @@ -23,11 +23,11 @@ export class ImplicitFlowCallbackService { hash?: string ): Observable { const isRenewProcess = this.flowsDataService.isSilentRenewRunning(config); - const { - triggerAuthorizationResultEvent, - postLoginRoute, - unauthorizedRoute, - } = config; + const triggerAuthorizationResultEvent = Boolean( + config.triggerAuthorizationResultEvent + ); + const postLoginRoute = config.postLoginRoute ?? ''; + const unauthorizedRoute = config.unauthorizedRoute ?? ''; return this.flowsService .processImplicitFlowCallback(config, allConfigs, hash) diff --git a/projects/angular-auth-oidc-client/src/lib/callback/interval.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/callback/interval.service.spec.ts index 6fe238aa0..2e124f505 100644 --- a/projects/angular-auth-oidc-client/src/lib/callback/interval.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/callback/interval.service.spec.ts @@ -7,7 +7,16 @@ describe('IntervalService', () => { beforeEach(() => { TestBed.configureTestingModule({ - providers: [IntervalService], + providers: [ + { + provide: Document, + useValue: { + defaultView: { + setInterval: window.setInterval, + }, + }, + }, + ], }); }); diff --git a/projects/angular-auth-oidc-client/src/lib/callback/interval.service.ts b/projects/angular-auth-oidc-client/src/lib/callback/interval.service.ts index 483402f94..25d963f16 100644 --- a/projects/angular-auth-oidc-client/src/lib/callback/interval.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/callback/interval.service.ts @@ -1,14 +1,16 @@ -import { Injectable, NgZone } from '@angular/core'; -import { Observable } from 'rxjs'; +import { Injectable, NgZone, inject } from '@angular/core'; +import { Observable, Subscription } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class IntervalService { - runTokenValidationRunning = null; + private readonly zone = inject(NgZone); - constructor(private readonly zone: NgZone) {} + private readonly document = inject(Document); + + runTokenValidationRunning: Subscription | null = null; isTokenValidationRunning(): boolean { - return !!this.runTokenValidationRunning; + return Boolean(this.runTokenValidationRunning); } stopPeriodicTokenCheck(): void { @@ -22,10 +24,10 @@ export class IntervalService { const millisecondsDelayBetweenTokenCheck = repeatAfterSeconds * 1000; return new Observable((subscriber) => { - let intervalId; + let intervalId: number | undefined; this.zone.runOutsideAngular(() => { - intervalId = setInterval( + intervalId = this.document?.defaultView?.setInterval( () => this.zone.run(() => subscriber.next()), millisecondsDelayBetweenTokenCheck ); diff --git a/projects/angular-auth-oidc-client/src/lib/callback/periodically-token-check.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/callback/periodically-token-check.service.spec.ts index 9e3e3d316..93e470e28 100644 --- a/projects/angular-auth-oidc-client/src/lib/callback/periodically-token-check.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/callback/periodically-token-check.service.spec.ts @@ -1,6 +1,6 @@ import { fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing'; import { of, throwError } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { AuthStateService } from '../auth-state/auth-state.service'; import { ConfigurationService } from '../config/config.service'; import { OpenIdConfiguration } from '../config/openid-configuration'; @@ -35,36 +35,18 @@ describe('PeriodicallyTokenCheckService', () => { TestBed.configureTestingModule({ imports: [], providers: [ - { - provide: ResetAuthDataService, - useClass: mockClass(ResetAuthDataService), - }, + mockProvider(ResetAuthDataService), FlowHelper, - { provide: FlowsDataService, useClass: mockClass(FlowsDataService) }, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { provide: UserService, useClass: mockClass(UserService) }, - { provide: AuthStateService, useClass: mockClass(AuthStateService) }, - { - provide: RefreshSessionIframeService, - useClass: mockClass(RefreshSessionIframeService), - }, - { - provide: RefreshSessionRefreshTokenService, - useClass: mockClass(RefreshSessionRefreshTokenService), - }, - IntervalService, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, - { - provide: PublicEventsService, - useClass: mockClass(PublicEventsService), - }, - { - provide: ConfigurationService, - useClass: mockClass(ConfigurationService), - }, + mockProvider(FlowsDataService), + mockProvider(LoggerService), + mockProvider(UserService), + mockProvider(AuthStateService), + mockProvider(RefreshSessionIframeService), + mockProvider(RefreshSessionRefreshTokenService), + mockProvider(IntervalService), + mockProvider(StoragePersistenceService), + mockProvider(PublicEventsService), + mockProvider(ConfigurationService), ], }); }); @@ -85,6 +67,8 @@ describe('PeriodicallyTokenCheckService', () => { resetAuthDataService = TestBed.inject(ResetAuthDataService); publicEventsService = TestBed.inject(PublicEventsService); configurationService = TestBed.inject(ConfigurationService); + + spyOn(intervalService, 'startPeriodicTokenCheck').and.returnValue(of(null)); }); afterEach(() => { @@ -161,7 +145,7 @@ describe('PeriodicallyTokenCheckService', () => { tick(1000); - intervalService.runTokenValidationRunning.unsubscribe(); + intervalService.runTokenValidationRunning?.unsubscribe(); intervalService.runTokenValidationRunning = null; expect(isCurrentFlowCodeFlowWithRefreshTokensSpy).toHaveBeenCalled(); expect(resetSilentRenewRunningSpy).toHaveBeenCalled(); @@ -172,9 +156,6 @@ describe('PeriodicallyTokenCheckService', () => { { silentRenew: true, configId: 'configId1', tokenRefreshInSeconds: 1 }, ]; - spyOn(intervalService, 'startPeriodicTokenCheck').and.returnValue( - of(null) - ); spyOn( periodicallyTokenCheckService as any, 'shouldStartPeriodicallyCheckForConfig' @@ -214,9 +195,6 @@ describe('PeriodicallyTokenCheckService', () => { { silentRenew: true, configId: 'configId1', tokenRefreshInSeconds: 1 }, ]; - spyOn(intervalService, 'startPeriodicTokenCheck').and.returnValue( - of(null) - ); spyOn( periodicallyTokenCheckService as any, 'shouldStartPeriodicallyCheckForConfig' @@ -282,7 +260,7 @@ describe('PeriodicallyTokenCheckService', () => { configs[0] ); tick(1000); - intervalService.runTokenValidationRunning.unsubscribe(); + intervalService.runTokenValidationRunning?.unsubscribe(); intervalService.runTokenValidationRunning = null; expect(resetAuthorizationDataSpy).toHaveBeenCalledTimes(1); @@ -321,7 +299,7 @@ describe('PeriodicallyTokenCheckService', () => { tick(1000); - intervalService.runTokenValidationRunning.unsubscribe(); + intervalService.runTokenValidationRunning?.unsubscribe(); intervalService.runTokenValidationRunning = null; expect(refreshSessionWithRefreshTokensSpy).toHaveBeenCalled(); })); @@ -329,7 +307,7 @@ describe('PeriodicallyTokenCheckService', () => { describe('shouldStartPeriodicallyCheckForConfig', () => { it('returns false when there is no IdToken', () => { - spyOn(authStateService, 'getIdToken').and.returnValue(null); + spyOn(authStateService, 'getIdToken').and.returnValue(''); spyOn(flowsDataService, 'isSilentRenewRunning').and.returnValue(false); spyOn(userService, 'getUserDataFromStore').and.returnValue( 'some-userdata' diff --git a/projects/angular-auth-oidc-client/src/lib/callback/periodically-token-check.service.ts b/projects/angular-auth-oidc-client/src/lib/callback/periodically-token-check.service.ts index 29c366f77..6ba61e918 100644 --- a/projects/angular-auth-oidc-client/src/lib/callback/periodically-token-check.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/callback/periodically-token-check.service.ts @@ -56,11 +56,15 @@ export class PeriodicallyTokenCheckService { .startPeriodicTokenCheck(refreshTimeInSeconds) .pipe( switchMap(() => { - const objectWithConfigIdsAndRefreshEvent = {}; + const objectWithConfigIdsAndRefreshEvent: { + [id: string]: Observable; + } = {}; configsWithSilentRenewEnabled.forEach((config) => { - objectWithConfigIdsAndRefreshEvent[config.configId] = - this.getRefreshEvent(config, allConfigs); + const identifier = config.configId as string; + const refreshEvent = this.getRefreshEvent(config, allConfigs); + + objectWithConfigIdsAndRefreshEvent[identifier] = refreshEvent; }); return forkJoin(objectWithConfigIdsAndRefreshEvent); @@ -101,7 +105,7 @@ export class PeriodicallyTokenCheckService { private getRefreshEvent( config: OpenIdConfiguration, allConfigs: OpenIdConfiguration[] - ): Observable { + ): Observable { const shouldStartRefreshEvent = this.shouldStartPeriodicallyCheckForConfig(config); @@ -128,10 +132,12 @@ export class PeriodicallyTokenCheckService { configsWithSilentRenewEnabled: OpenIdConfiguration[] ): number { const result = configsWithSilentRenewEnabled.reduce((prev, curr) => - prev.tokenRefreshInSeconds < curr.tokenRefreshInSeconds ? prev : curr + (prev.tokenRefreshInSeconds ?? 0) < (curr.tokenRefreshInSeconds ?? 0) + ? prev + : curr ); - return result.tokenRefreshInSeconds; + return result.tokenRefreshInSeconds ?? 0; } private getConfigsWithSilentRenewEnabled( @@ -143,7 +149,7 @@ export class PeriodicallyTokenCheckService { private createRefreshEventForConfig( configuration: OpenIdConfiguration, allConfigs: OpenIdConfiguration[] - ): Observable { + ): Observable { this.loggerService.logDebug(configuration, 'starting silent renew...'); return this.configurationService diff --git a/projects/angular-auth-oidc-client/src/lib/callback/refresh-session-refresh-token.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/callback/refresh-session-refresh-token.service.spec.ts index 2eb202828..6aab19d55 100644 --- a/projects/angular-auth-oidc-client/src/lib/callback/refresh-session-refresh-token.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/callback/refresh-session-refresh-token.service.spec.ts @@ -1,6 +1,7 @@ import { fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing'; import { of, throwError } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; +import { CallbackContext } from '../flows/callback-context'; import { FlowsService } from '../flows/flows.service'; import { ResetAuthDataService } from '../flows/reset-auth-data.service'; import { LoggerService } from '../logging/logger.service'; @@ -18,13 +19,10 @@ describe('RefreshSessionRefreshTokenService', () => { imports: [], providers: [ RefreshSessionRefreshTokenService, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { provide: FlowsService, useClass: mockClass(FlowsService) }, - { - provide: ResetAuthDataService, - useClass: mockClass(ResetAuthDataService), - }, - IntervalService, + mockProvider(LoggerService), + mockProvider(FlowsService), + mockProvider(ResetAuthDataService), + mockProvider(IntervalService), ], }); }); @@ -45,7 +43,7 @@ describe('RefreshSessionRefreshTokenService', () => { describe('refreshSessionWithRefreshTokens', () => { it('calls flowsService.processRefreshToken()', waitForAsync(() => { const spy = spyOn(flowsService, 'processRefreshToken').and.returnValue( - of(null) + of({} as CallbackContext) ); refreshSessionRefreshTokenService diff --git a/projects/angular-auth-oidc-client/src/lib/callback/refresh-session.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/callback/refresh-session.service.spec.ts index 6188ba4c2..4a384dd08 100644 --- a/projects/angular-auth-oidc-client/src/lib/callback/refresh-session.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/callback/refresh-session.service.spec.ts @@ -1,7 +1,7 @@ import { fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing'; import { of, throwError } from 'rxjs'; import { delay } from 'rxjs/operators'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { AuthStateService } from '../auth-state/auth-state.service'; import { AuthWellKnownService } from '../config/auth-well-known/auth-well-known.service'; import { CallbackContext } from '../flows/callback-context'; @@ -34,31 +34,16 @@ describe('RefreshSessionService ', () => { imports: [], providers: [ FlowHelper, - { provide: FlowsDataService, useClass: mockClass(FlowsDataService) }, + mockProvider(FlowsDataService), RefreshSessionService, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { - provide: SilentRenewService, - useClass: mockClass(SilentRenewService), - }, - { provide: AuthStateService, useClass: mockClass(AuthStateService) }, - { - provide: AuthWellKnownService, - useClass: mockClass(AuthWellKnownService), - }, - { - provide: RefreshSessionIframeService, - useClass: mockClass(RefreshSessionIframeService), - }, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, - { - provide: RefreshSessionRefreshTokenService, - useClass: mockClass(RefreshSessionRefreshTokenService), - }, - { provide: UserService, useClass: mockClass(UserService) }, + mockProvider(LoggerService), + mockProvider(SilentRenewService), + mockProvider(AuthStateService), + mockProvider(AuthWellKnownService), + mockProvider(RefreshSessionIframeService), + mockProvider(StoragePersistenceService), + mockProvider(RefreshSessionRefreshTokenService), + mockProvider(UserService), ], }); }); @@ -502,7 +487,7 @@ describe('RefreshSessionService ', () => { (refreshSessionService as any) .startRefreshSession() - .subscribe((result) => { + .subscribe((result: any) => { expect(result).toBe(null); }); })); @@ -512,7 +497,7 @@ describe('RefreshSessionService ', () => { (refreshSessionService as any) .startRefreshSession() - .subscribe((result) => { + .subscribe((result: any) => { expect(result).toBe(null); }); })); @@ -542,7 +527,7 @@ describe('RefreshSessionService ', () => { spyOn( refreshSessionRefreshTokenService, 'refreshSessionWithRefreshTokens' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); (refreshSessionService as any) .startRefreshSession(allConfigs[0], allConfigs) @@ -573,7 +558,7 @@ describe('RefreshSessionService ', () => { const refreshSessionWithRefreshTokensSpy = spyOn( refreshSessionRefreshTokenService, 'refreshSessionWithRefreshTokens' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); (refreshSessionService as any) .startRefreshSession(allConfigs[0], allConfigs) @@ -604,12 +589,12 @@ describe('RefreshSessionService ', () => { const refreshSessionWithRefreshTokensSpy = spyOn( refreshSessionRefreshTokenService, 'refreshSessionWithRefreshTokens' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const refreshSessionWithIframeSpy = spyOn( refreshSessionIframeService, 'refreshSessionWithIframe' - ).and.returnValue(of(null)); + ).and.returnValue(of(false)); (refreshSessionService as any) .startRefreshSession(allConfigs[0], allConfigs) diff --git a/projects/angular-auth-oidc-client/src/lib/callback/refresh-session.service.ts b/projects/angular-auth-oidc-client/src/lib/callback/refresh-session.service.ts index a32a2384f..b4e42f65c 100644 --- a/projects/angular-auth-oidc-client/src/lib/callback/refresh-session.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/callback/refresh-session.service.ts @@ -47,10 +47,19 @@ export class RefreshSessionService { ) {} userForceRefreshSession( - config: OpenIdConfiguration, + config: OpenIdConfiguration | null, allConfigs: OpenIdConfiguration[], extraCustomParams?: { [key: string]: string | number | boolean } ): Observable { + if (!config) { + return throwError( + () => + new Error( + 'Please provide a configuration before setting up the module' + ) + ); + } + this.persistCustomParams(extraCustomParams, config); return this.forceRefreshSession(config, allConfigs, extraCustomParams); @@ -96,22 +105,45 @@ export class RefreshSessionService { } const { silentRenewTimeoutInSeconds } = config; - const timeOutTime = silentRenewTimeoutInSeconds * 1000; + const timeOutTime = (silentRenewTimeoutInSeconds ?? 0) * 1000; return forkJoin([ this.startRefreshSession(config, allConfigs, extraCustomParams), this.silentRenewService.refreshSessionWithIFrameCompleted$.pipe(take(1)), ]).pipe( timeout(timeOutTime), - retryWhen(this.timeoutRetryStrategy.bind(this)), + retryWhen((errors) => { + return errors.pipe( + mergeMap((error, index) => { + const scalingDuration = 1000; + const currentAttempt = index + 1; + + if ( + !(error instanceof TimeoutError) || + currentAttempt > MAX_RETRY_ATTEMPTS + ) { + return throwError(() => new Error(error)); + } + + this.loggerService.logDebug( + config, + `forceRefreshSession timeout. Attempt #${currentAttempt}` + ); + + this.flowsDataService.resetSilentRenewRunning(config); + + return timer(currentAttempt * scalingDuration); + }) + ); + }), map(([_, callbackContext]) => { const isAuthenticated = this.authStateService.areAuthStorageTokensValid(config); if (isAuthenticated) { return { - idToken: callbackContext?.authResult?.id_token, - accessToken: callbackContext?.authResult?.access_token, + idToken: callbackContext?.authResult?.id_token ?? '', + accessToken: callbackContext?.authResult?.access_token ?? '', userData: this.userService.getUserDataFromStore(config), isAuthenticated, configId, @@ -194,32 +226,4 @@ export class RefreshSessionService { }) ); } - - private timeoutRetryStrategy( - errorAttempts: Observable, - config: OpenIdConfiguration - ): Observable { - return errorAttempts.pipe( - mergeMap((error, index) => { - const scalingDuration = 1000; - const currentAttempt = index + 1; - - if ( - !(error instanceof TimeoutError) || - currentAttempt > MAX_RETRY_ATTEMPTS - ) { - return throwError(() => new Error(error)); - } - - this.loggerService.logDebug( - config, - `forceRefreshSession timeout. Attempt #${currentAttempt}` - ); - - this.flowsDataService.resetSilentRenewRunning(config); - - return timer(currentAttempt * scalingDuration); - }) - ); - } } diff --git a/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known-data.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known-data.service.spec.ts index eb2c0be41..b901cc2c4 100644 --- a/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known-data.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known-data.service.spec.ts @@ -1,6 +1,6 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { of, throwError } from 'rxjs'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { createRetriableStream } from '../../../test/create-retriable-stream.helper'; import { DataService } from '../../api/data.service'; import { LoggerService } from '../../logging/logger.service'; @@ -33,8 +33,8 @@ describe('AuthWellKnownDataService', () => { TestBed.configureTestingModule({ providers: [ AuthWellKnownDataService, - { provide: DataService, useClass: mockClass(DataService) }, - { provide: LoggerService, useClass: mockClass(LoggerService) }, + mockProvider(DataService), + mockProvider(LoggerService), ], }); }); @@ -51,9 +51,9 @@ describe('AuthWellKnownDataService', () => { describe('getWellKnownDocument', () => { it('should add suffix if it does not exist on current URL', waitForAsync(() => { - const dataServiceSpy = spyOn(dataService, 'get').and.callFake(() => { - return of(null); - }); + const dataServiceSpy = spyOn(dataService, 'get').and.returnValue( + of(null) + ); const urlWithoutSuffix = 'myUrl'; const urlWithSuffix = `${urlWithoutSuffix}/.well-known/openid-configuration`; @@ -67,9 +67,9 @@ describe('AuthWellKnownDataService', () => { })); it('should not add suffix if it does exist on current url', waitForAsync(() => { - const dataServiceSpy = spyOn(dataService, 'get').and.callFake(() => { - return of(null); - }); + const dataServiceSpy = spyOn(dataService, 'get').and.returnValue( + of(null) + ); const urlWithSuffix = `myUrl/.well-known/openid-configuration`; (service as any) @@ -82,9 +82,9 @@ describe('AuthWellKnownDataService', () => { })); it('should not add suffix if it does exist in the middle of current url', waitForAsync(() => { - const dataServiceSpy = spyOn(dataService, 'get').and.callFake(() => { - return of(null); - }); + const dataServiceSpy = spyOn(dataService, 'get').and.returnValue( + of(null) + ); const urlWithSuffix = `myUrl/.well-known/openid-configuration/and/some/more/stuff`; (service as any) @@ -107,7 +107,7 @@ describe('AuthWellKnownDataService', () => { (service as any) .getWellKnownDocument('anyurl', { configId: 'configId1' }) .subscribe({ - next: (res) => { + next: (res: any) => { expect(res).toBeTruthy(); expect(res).toEqual(DUMMY_WELL_KNOWN_DOCUMENT); }, @@ -126,7 +126,7 @@ describe('AuthWellKnownDataService', () => { (service as any) .getWellKnownDocument('anyurl', { configId: 'configId1' }) .subscribe({ - next: (res) => { + next: (res: any) => { expect(res).toBeTruthy(); expect(res).toEqual(DUMMY_WELL_KNOWN_DOCUMENT); }, @@ -144,7 +144,7 @@ describe('AuthWellKnownDataService', () => { ); (service as any).getWellKnownDocument('anyurl', 'configId').subscribe({ - error: (err) => { + error: (err: any) => { expect(err).toBeTruthy(); }, }); @@ -153,9 +153,7 @@ describe('AuthWellKnownDataService', () => { describe('getWellKnownEndPointsForConfig', () => { it('calling internal getWellKnownDocument and maps', waitForAsync(() => { - spyOn(dataService, 'get').and.returnValue( - of({ jwks_uri: 'jwks_uri' }) - ); + spyOn(dataService, 'get').and.returnValue(of({ jwks_uri: 'jwks_uri' })); const spy = spyOn( service as any, @@ -176,7 +174,10 @@ describe('AuthWellKnownDataService', () => { it('throws error and logs if no authwellknownUrl is given', waitForAsync(() => { const loggerSpy = spyOn(loggerService, 'logError'); - const config = { configId: 'configId1', authWellknownEndpointUrl: null }; + const config = { + configId: 'configId1', + authWellknownEndpointUrl: undefined, + }; service.getWellKnownEndPointsForConfig(config).subscribe({ error: (error) => { diff --git a/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known-data.service.ts b/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known-data.service.ts index 32ac585c9..48115bdd9 100644 --- a/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known-data.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known-data.service.ts @@ -58,6 +58,6 @@ export class AuthWellKnownDataService { url = `${wellKnownEndpoint}${WELL_KNOWN_SUFFIX}`; } - return this.http.get(url, config).pipe(retry(2)); + return this.http.get(url, config).pipe(retry(2)); } } diff --git a/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known.service.spec.ts index c8152dfb5..2e61fd57b 100644 --- a/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known.service.spec.ts @@ -1,6 +1,6 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { of, throwError } from 'rxjs'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { EventTypes } from '../../public-events/event-types'; import { PublicEventsService } from '../../public-events/public-events.service'; import { StoragePersistenceService } from '../../storage/storage-persistence.service'; @@ -18,14 +18,8 @@ describe('AuthWellKnownService', () => { providers: [ AuthWellKnownService, PublicEventsService, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, - { - provide: AuthWellKnownDataService, - useClass: mockClass(AuthWellKnownDataService), - }, + mockProvider(AuthWellKnownDataService), + mockProvider(StoragePersistenceService), ], }); }); diff --git a/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known.service.ts b/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known.service.ts index ca859274a..af861dad3 100644 --- a/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known.service.ts @@ -28,8 +28,17 @@ export class AuthWellKnownService { } queryAndStoreAuthWellKnownEndPoints( - config: OpenIdConfiguration + config: OpenIdConfiguration | null ): Observable { + if (!config) { + return throwError( + () => + new Error( + 'Please provide a configuration before setting up the module' + ) + ); + } + const alreadySavedWellKnownEndpoints = this.storagePersistenceService.read( 'authWellKnownEndPoints', config diff --git a/projects/angular-auth-oidc-client/src/lib/config/config.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/config/config.service.spec.ts index 075c2a6df..fe7ba74e9 100644 --- a/projects/angular-auth-oidc-client/src/lib/config/config.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/config/config.service.spec.ts @@ -1,6 +1,6 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { of } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockAbstractProvider, mockProvider } from '../../test/auto-mock'; import { LoggerService } from '../logging/logger.service'; import { EventTypes } from '../public-events/event-types'; import { PublicEventsService } from '../public-events/public-events.service'; @@ -25,28 +25,13 @@ describe('Configuration Service', () => { TestBed.configureTestingModule({ providers: [ ConfigurationService, - { - provide: LoggerService, - useClass: mockClass(LoggerService), - }, + mockProvider(LoggerService), PublicEventsService, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, + mockProvider(StoragePersistenceService), ConfigValidationService, - { - provide: PlatformProvider, - useClass: mockClass(PlatformProvider), - }, - { - provide: AuthWellKnownService, - useClass: mockClass(AuthWellKnownService), - }, - { - provide: StsConfigLoader, - useClass: mockClass(StsConfigStaticLoader), - }, + mockProvider(PlatformProvider), + mockProvider(AuthWellKnownService), + mockAbstractProvider(StsConfigLoader, StsConfigStaticLoader), ], }); }); @@ -165,7 +150,7 @@ describe('Configuration Service', () => { }); configService.getOpenIDConfiguration('configId1').subscribe((config) => { - expect(config.authWellknownEndpoints).toEqual({ + expect(config?.authWellknownEndpoints).toEqual({ issuer: 'auth-well-known', }); }); @@ -214,9 +199,12 @@ describe('Configuration Service', () => { EventTypes.ConfigLoaded, jasmine.anything() ); - expect(storeWellKnownEndpointsSpy).toHaveBeenCalledOnceWith(config, { - issuer: 'auth-well-known', - }); + expect(storeWellKnownEndpointsSpy).toHaveBeenCalledOnceWith( + config as OpenIdConfiguration, + { + issuer: 'auth-well-known', + } + ); }); })); }); @@ -255,11 +243,11 @@ describe('Configuration Service', () => { expect(allConfigIds).toEqual(['0-clientId1', '1-clientId2']); expect(result.currentConfig).toBeTruthy(); - expect(result.currentConfig.configId).toBeTruthy(); + expect(result.currentConfig?.configId).toBeTruthy(); }); })); - it(`returns null if config is not valid`, waitForAsync(() => { + it(`returns empty array if config is not valid`, waitForAsync(() => { spyOn(stsConfigLoader, 'loadConfigs').and.returnValue( of([ { configId: 'configId1' } as OpenIdConfiguration, @@ -272,7 +260,7 @@ describe('Configuration Service', () => { configService .getOpenIDConfigurations() .subscribe(({ allConfigs, currentConfig }) => { - expect(allConfigs).toBeNull(); + expect(allConfigs).toEqual([]); expect(currentConfig).toBeNull(); }); })); diff --git a/projects/angular-auth-oidc-client/src/lib/config/config.service.ts b/projects/angular-auth-oidc-client/src/lib/config/config.service.ts index d44e6d8b8..ba0934ace 100644 --- a/projects/angular-auth-oidc-client/src/lib/config/config.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/config/config.service.ts @@ -34,7 +34,9 @@ export class ConfigurationService { return Object.values(this.configsInternal); } - getOpenIDConfiguration(configId?: string): Observable { + getOpenIDConfiguration( + configId?: string + ): Observable { if (this.configsAlreadySaved()) { return of(this.getConfig(configId)); } @@ -44,9 +46,10 @@ export class ConfigurationService { ); } - getOpenIDConfigurations( - configId?: string - ): Observable<{ allConfigs; currentConfig }> { + getOpenIDConfigurations(configId?: string): Observable<{ + allConfigs: OpenIdConfiguration[]; + currentConfig: OpenIdConfiguration | null; + }> { return this.loadConfigs().pipe( concatMap((allConfigs) => this.prepareAndSaveConfigs(allConfigs)), map((allPreparedConfigs) => ({ @@ -63,7 +66,7 @@ export class ConfigurationService { private saveConfig(readyConfig: OpenIdConfiguration): void { const { configId } = readyConfig; - this.configsInternal[configId] = readyConfig; + this.configsInternal[configId as string] = readyConfig; } private loadConfigs(): Observable { @@ -74,9 +77,9 @@ export class ConfigurationService { return this.hasAtLeastOneConfig(); } - private getConfig(configId: string): OpenIdConfiguration { - if (!!configId) { - return this.configsInternal[configId] || null; + private getConfig(configId?: string): OpenIdConfiguration | null { + if (Boolean(configId)) { + return this.configsInternal[configId as string] || null; } const [, value] = Object.entries(this.configsInternal)[0] || [[null, null]]; @@ -88,13 +91,18 @@ export class ConfigurationService { passedConfigs: OpenIdConfiguration[] ): Observable { if (!this.configValidationService.validateConfigs(passedConfigs)) { - return of(null); + return of([]); } this.createUniqueIds(passedConfigs); + const allHandleConfigs$ = passedConfigs.map((x) => this.handleConfig(x)); + const as = forkJoin(allHandleConfigs$).pipe( + map((config) => config.filter((conf) => Boolean(conf))), + map((c) => c as OpenIdConfiguration[]) + ); - return forkJoin(allHandleConfigs$); + return as; } private createUniqueIds(passedConfigs: OpenIdConfiguration[]): void { @@ -107,7 +115,7 @@ export class ConfigurationService { private handleConfig( passedConfig: OpenIdConfiguration - ): Observable { + ): Observable { if (!this.configValidationService.validateConfig(passedConfig)) { this.loggerService.logError( passedConfig, diff --git a/projects/angular-auth-oidc-client/src/lib/config/default-config.ts b/projects/angular-auth-oidc-client/src/lib/config/default-config.ts index 2bfd24470..29b3ee3b7 100644 --- a/projects/angular-auth-oidc-client/src/lib/config/default-config.ts +++ b/projects/angular-auth-oidc-client/src/lib/config/default-config.ts @@ -4,7 +4,7 @@ import { OpenIdConfiguration } from './openid-configuration'; export const DEFAULT_CONFIG: OpenIdConfiguration = { authority: 'https://please_set', authWellknownEndpointUrl: '', - authWellknownEndpoints: null, + authWellknownEndpoints: undefined, redirectUrl: 'https://please_set', clientId: 'please_set', responseType: 'code', diff --git a/projects/angular-auth-oidc-client/src/lib/config/validation/config-validation.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/config/validation/config-validation.service.spec.ts index 6a8cee750..7bf529fb0 100644 --- a/projects/angular-auth-oidc-client/src/lib/config/validation/config-validation.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/config/validation/config-validation.service.spec.ts @@ -1,7 +1,8 @@ import { TestBed } from '@angular/core/testing'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { LogLevel } from '../../logging/log-level'; import { LoggerService } from '../../logging/logger.service'; +import { OpenIdConfiguration } from '../openid-configuration'; import { ConfigValidationService } from './config-validation.service'; import { allMultipleConfigRules } from './rules'; @@ -11,10 +12,7 @@ describe('Config Validation Service', () => { beforeEach(() => { TestBed.configureTestingModule({ - providers: [ - ConfigValidationService, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - ], + providers: [ConfigValidationService, mockProvider(LoggerService)], }); }); @@ -71,7 +69,7 @@ describe('Config Validation Service', () => { describe('ensure-clientId.rule', () => { it('return false when no clientId is set', () => { - const config = { ...VALID_CONFIG, clientId: null }; + const config = { ...VALID_CONFIG, clientId: '' } as OpenIdConfiguration; const result = configValidationService.validateConfig(config); expect(result).toBeFalse(); @@ -80,7 +78,10 @@ describe('Config Validation Service', () => { describe('ensure-authority-server.rule', () => { it('return false when no security token service is set', () => { - const config = { ...VALID_CONFIG, authority: null }; + const config = { + ...VALID_CONFIG, + authority: '', + } as OpenIdConfiguration; const result = configValidationService.validateConfig(config); expect(result).toBeFalse(); @@ -102,8 +103,8 @@ describe('Config Validation Service', () => { ...VALID_CONFIG, silentRenew: true, useRefreshToken: false, - silentRenewUrl: null, - }; + silentRenewUrl: '', + } as OpenIdConfiguration; const result = configValidationService.validateConfig(config); expect(result).toBeFalse(); @@ -166,17 +167,12 @@ describe('Config Validation Service', () => { }); it('should return false and a better error message when config is not passed as object with config property', () => { - const loggerErrorSpy = spyOn(loggerService, 'logError'); const loggerWarningSpy = spyOn(loggerService, 'logWarning'); - const result = configValidationService.validateConfigs([null]); + const result = configValidationService.validateConfigs([]); expect(result).toBeFalse(); expect(loggerWarningSpy).not.toHaveBeenCalled(); - expect(loggerErrorSpy.calls.argsFor(0)).toEqual([ - null, - `Please make sure you add an object with a 'config' property: ....({ config }) instead of ...(config)`, - ]); }); }); @@ -187,9 +183,9 @@ describe('Config Validation Service', () => { 'validateConfigsInternal' ).and.callThrough(); - const result = configValidationService.validateConfigs(null); + const result = configValidationService.validateConfigs([]); - expect(result).toBeTrue(); + expect(result).toBeFalse(); expect(spy).toHaveBeenCalledOnceWith([], allMultipleConfigRules); }); }); diff --git a/projects/angular-auth-oidc-client/src/lib/config/validation/config-validation.service.ts b/projects/angular-auth-oidc-client/src/lib/config/validation/config-validation.service.ts index e0395c228..0260c1615 100644 --- a/projects/angular-auth-oidc-client/src/lib/config/validation/config-validation.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/config/validation/config-validation.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { LoggerService } from '../../logging/logger.service'; import { OpenIdConfiguration } from '../openid-configuration'; import { Level, RuleValidationResult } from './rule'; -import { allRules, allMultipleConfigRules } from './rules'; +import { allMultipleConfigRules, allRules } from './rules'; @Injectable({ providedIn: 'root' }) export class ConfigValidationService { @@ -23,6 +23,10 @@ export class ConfigValidationService { passedConfigs: OpenIdConfiguration[], allRulesToUse: any[] ): boolean { + if (passedConfigs.length === 0) { + return false; + } + const allValidationResults = allRulesToUse.map((rule) => rule(passedConfigs) ); diff --git a/projects/angular-auth-oidc-client/src/lib/config/validation/rule.ts b/projects/angular-auth-oidc-client/src/lib/config/validation/rule.ts index 610c75e4f..69cbdd608 100644 --- a/projects/angular-auth-oidc-client/src/lib/config/validation/rule.ts +++ b/projects/angular-auth-oidc-client/src/lib/config/validation/rule.ts @@ -10,10 +10,10 @@ export interface RuleValidationResult { level: Level; } -export const POSITIVE_VALIDATION_RESULT = { +export const POSITIVE_VALIDATION_RESULT: RuleValidationResult = { result: true, messages: [], - level: null, + level: 'none', }; -export type Level = 'warning' | 'error'; +export type Level = 'warning' | 'error' | 'none'; diff --git a/projects/angular-auth-oidc-client/src/lib/config/validation/rules/ensure-no-duplicated-configs.rule.ts b/projects/angular-auth-oidc-client/src/lib/config/validation/rules/ensure-no-duplicated-configs.rule.ts index 41ceae5c7..4f9b4e764 100644 --- a/projects/angular-auth-oidc-client/src/lib/config/validation/rules/ensure-no-duplicated-configs.rule.ts +++ b/projects/angular-auth-oidc-client/src/lib/config/validation/rules/ensure-no-duplicated-configs.rule.ts @@ -3,7 +3,7 @@ import { POSITIVE_VALIDATION_RESULT, RuleValidationResult } from '../rule'; const createIdentifierToCheck = (passedConfig: OpenIdConfiguration): string => { if (!passedConfig) { - return null; + return ''; } const { authority, clientId, scope } = passedConfig; @@ -19,9 +19,9 @@ export const ensureNoDuplicatedConfigsRule = ( ): RuleValidationResult => { const allIdentifiers = passedConfigs.map((x) => createIdentifierToCheck(x)); - const someAreNull = allIdentifiers.some((x) => x === null); + const someAreNotSet = allIdentifiers.some((x) => x === ''); - if (someAreNull) { + if (someAreNotSet) { return { result: false, messages: [ diff --git a/projects/angular-auth-oidc-client/src/lib/extractors/jwk.extractor.ts b/projects/angular-auth-oidc-client/src/lib/extractors/jwk.extractor.ts index 54016e42f..7c93a127d 100644 --- a/projects/angular-auth-oidc-client/src/lib/extractors/jwk.extractor.ts +++ b/projects/angular-auth-oidc-client/src/lib/extractors/jwk.extractor.ts @@ -12,7 +12,7 @@ export class JwkExtractor { } const foundKeys = keys - .filter((k) => (spec?.kid ? k['kid'] === spec.kid : true)) + .filter((k) => (spec?.kid ? (k as any)['kid'] === spec.kid : true)) .filter((k) => (spec?.use ? k['use'] === spec.use : true)) .filter((k) => (spec?.kty ? k['kty'] === spec.kty : true)); diff --git a/projects/angular-auth-oidc-client/src/lib/flows/callback-context.ts b/projects/angular-auth-oidc-client/src/lib/flows/callback-context.ts index fe96cdee7..184adf01a 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/callback-context.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/callback-context.ts @@ -6,10 +6,10 @@ export interface CallbackContext { refreshToken: string; state: string; sessionState: string | null; - authResult: AuthResult; + authResult: AuthResult | null; isRenewProcess: boolean; - jwtKeys: JwtKeys; - validationResult: StateValidationResult; + jwtKeys: JwtKeys | null; + validationResult: StateValidationResult | null; existingIdToken: any; } diff --git a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/code-flow-callback-handler.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/code-flow-callback-handler.service.spec.ts index f27a94b6d..09ff2515a 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/code-flow-callback-handler.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/code-flow-callback-handler.service.spec.ts @@ -1,7 +1,7 @@ import { HttpErrorResponse, HttpHeaders } from '@angular/common/http'; import { TestBed, waitForAsync } from '@angular/core/testing'; import { of, throwError } from 'rxjs'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { createRetriableStream } from '../../../test/create-retriable-stream.helper'; import { DataService } from '../../api/data.service'; import { LoggerService } from '../../logging/logger.service'; @@ -23,18 +23,12 @@ describe('CodeFlowCallbackHandlerService', () => { TestBed.configureTestingModule({ providers: [ CodeFlowCallbackHandlerService, - { provide: UrlService, useClass: mockClass(UrlService) }, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { - provide: TokenValidationService, - useClass: mockClass(TokenValidationService), - }, - { provide: FlowsDataService, useClass: mockClass(FlowsDataService) }, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, - { provide: DataService, useClass: mockClass(DataService) }, + mockProvider(UrlService), + mockProvider(LoggerService), + mockProvider(TokenValidationService), + mockProvider(FlowsDataService), + mockProvider(StoragePersistenceService), + mockProvider(DataService), ], }); }); @@ -58,7 +52,7 @@ describe('CodeFlowCallbackHandlerService', () => { 'getUrlParameter' ).and.returnValue('params'); - getUrlParameterSpy.withArgs('any-url', 'state').and.returnValue(null); + getUrlParameterSpy.withArgs('any-url', 'state').and.returnValue(''); service.codeFlowCallback('any-url', { configId: 'configId1' }).subscribe({ error: (err) => { @@ -73,7 +67,7 @@ describe('CodeFlowCallbackHandlerService', () => { 'getUrlParameter' ).and.returnValue('params'); - getUrlParameterSpy.withArgs('any-url', 'code').and.returnValue(null); + getUrlParameterSpy.withArgs('any-url', 'code').and.returnValue(''); service.codeFlowCallback('any-url', { configId: 'configId1' }).subscribe({ error: (err) => { @@ -87,7 +81,7 @@ describe('CodeFlowCallbackHandlerService', () => { const expectedCallbackContext = { code: 'params', - refreshToken: null, + refreshToken: '', state: 'params', sessionState: 'params', authResult: null, @@ -95,7 +89,7 @@ describe('CodeFlowCallbackHandlerService', () => { jwtKeys: null, validationResult: null, existingIdToken: null, - }; + } as CallbackContext; service .codeFlowCallback('any-url', { configId: 'configId1' }) diff --git a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/code-flow-callback-handler.service.ts b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/code-flow-callback-handler.service.ts index 735de224b..7664818e5 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/code-flow-callback-handler.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/code-flow-callback-handler.service.ts @@ -52,9 +52,9 @@ export class CodeFlowCallbackHandlerService { urlToCheck ); - const initialCallbackContext = { + const initialCallbackContext: CallbackContext = { code, - refreshToken: null, + refreshToken: '', state, sessionState, authResult: null, @@ -107,12 +107,16 @@ export class CodeFlowCallbackHandlerService { return this.dataService .post(tokenEndpoint, bodyForCodeFlow, config, headers) .pipe( - switchMap((response: AuthResult) => { - callbackContext.authResult = { - ...response, - state: callbackContext.state, - session_state: callbackContext.sessionState, - }; + switchMap((response) => { + if (response) { + const authResult: AuthResult = { + ...response, + state: callbackContext.state, + session_state: callbackContext.sessionState, + }; + + callbackContext.authResult = authResult; + } return of(callbackContext); }), @@ -146,7 +150,7 @@ export class CodeFlowCallbackHandlerService { this.loggerService.logWarning(config, errorMessage, error); - return timer(refreshTokenRetryInSeconds * 1000); + return timer((refreshTokenRetryInSeconds ?? 0) * 1000); } return throwError(() => error); diff --git a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/history-jwt-keys-callback-handler.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/history-jwt-keys-callback-handler.service.spec.ts index ed6e6c048..754420c22 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/history-jwt-keys-callback-handler.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/history-jwt-keys-callback-handler.service.spec.ts @@ -1,12 +1,12 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { of, throwError } from 'rxjs'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { AuthStateService } from '../../auth-state/auth-state.service'; import { LoggerService } from '../../logging/logger.service'; import { StoragePersistenceService } from '../../storage/storage-persistence.service'; import { JwtKey, JwtKeys } from '../../validation/jwtkeys'; import { ValidationResult } from '../../validation/validation-result'; -import { CallbackContext, AuthResult } from '../callback-context'; +import { AuthResult, CallbackContext } from '../callback-context'; import { FlowsDataService } from '../flows-data.service'; import { ResetAuthDataService } from '../reset-auth-data.service'; import { SigninKeyDataService } from '../signin-key-data.service'; @@ -38,21 +38,12 @@ describe('HistoryJwtKeysCallbackHandlerService', () => { TestBed.configureTestingModule({ providers: [ HistoryJwtKeysCallbackHandlerService, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { provide: AuthStateService, useClass: mockClass(AuthStateService) }, - { provide: FlowsDataService, useClass: mockClass(FlowsDataService) }, - { - provide: SigninKeyDataService, - useClass: mockClass(SigninKeyDataService), - }, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, - { - provide: ResetAuthDataService, - useClass: mockClass(ResetAuthDataService), - }, + mockProvider(LoggerService), + mockProvider(AuthStateService), + mockProvider(FlowsDataService), + mockProvider(SigninKeyDataService), + mockProvider(StoragePersistenceService), + mockProvider(ResetAuthDataService), ], }); }); @@ -272,7 +263,9 @@ describe('HistoryJwtKeysCallbackHandlerService', () => { }, ]; - spyOn(signInKeyDataService, 'getSigningKeys').and.returnValue(of(null)); + spyOn(signInKeyDataService, 'getSigningKeys').and.returnValue( + of({} as JwtKeys) + ); service .callbackHistoryAndResetJwtKeys( callbackContext, @@ -350,6 +343,7 @@ describe('HistoryJwtKeysCallbackHandlerService', () => { it('calls resetAuthorizationData, resets nonce and authStateService in case of an error', waitForAsync(() => { const callbackContext = { authResult: { error: 'someError' }, + isRenewProcess: false, } as CallbackContext; const allconfigs = [ { @@ -381,7 +375,7 @@ describe('HistoryJwtKeysCallbackHandlerService', () => { expect(updateAndPublishAuthStateSpy).toHaveBeenCalledOnceWith({ isAuthenticated: false, validationResult: ValidationResult.SecureTokenServerError, - isRenewProcess: undefined, + isRenewProcess: false, }); }, }); @@ -390,6 +384,7 @@ describe('HistoryJwtKeysCallbackHandlerService', () => { it('calls authStateService.updateAndPublishAuthState with login required if the error is `login_required`', waitForAsync(() => { const callbackContext = { authResult: { error: 'login_required' }, + isRenewProcess: false, } as CallbackContext; const allconfigs = [ { @@ -421,7 +416,7 @@ describe('HistoryJwtKeysCallbackHandlerService', () => { expect(updateAndPublishAuthStateSpy).toHaveBeenCalledOnceWith({ isAuthenticated: false, validationResult: ValidationResult.LoginRequired, - isRenewProcess: undefined, + isRenewProcess: false, }); }, }); diff --git a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/history-jwt-keys-callback-handler.service.ts b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/history-jwt-keys-callback-handler.service.ts index 3aa01934e..a1a66b6e8 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/history-jwt-keys-callback-handler.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/history-jwt-keys-callback-handler.service.ts @@ -48,7 +48,7 @@ export class HistoryJwtKeysCallbackHandlerService { if ( config.allowUnsafeReuseRefreshToken && - callbackContext.authResult.refresh_token + callbackContext.authResult?.refresh_token ) { this.storagePersistenceService.write( 'reusable_refresh_token', @@ -66,7 +66,7 @@ export class HistoryJwtKeysCallbackHandlerService { this.loggerService.logDebug(config, 'history clean up inactive'); } - if (callbackContext.authResult.error) { + if (callbackContext.authResult?.error) { const errorMessage = `AuthCallback AuthResult came with error: ${callbackContext.authResult.error}`; this.loggerService.logDebug(config, errorMessage); @@ -154,7 +154,7 @@ export class HistoryJwtKeysCallbackHandlerService { } private resetBrowserHistory(): void { - this.document.defaultView.history.replaceState( + this.document.defaultView?.history.replaceState( {}, this.document.title, this.document.defaultView.location.origin + diff --git a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/implicit-flow-callback-handler.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/implicit-flow-callback-handler.service.spec.ts index 77fba238c..4f1ec1db2 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/implicit-flow-callback-handler.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/implicit-flow-callback-handler.service.spec.ts @@ -1,6 +1,6 @@ import { DOCUMENT } from '@angular/common'; import { TestBed, waitForAsync } from '@angular/core/testing'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { LoggerService } from '../../logging/logger.service'; import { CallbackContext } from '../callback-context'; import { FlowsDataService } from '../flows-data.service'; @@ -16,12 +16,9 @@ describe('ImplicitFlowCallbackHandlerService', () => { TestBed.configureTestingModule({ providers: [ ImplicitFlowCallbackHandlerService, - { - provide: ResetAuthDataService, - useClass: mockClass(ResetAuthDataService), - }, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { provide: FlowsDataService, useClass: mockClass(FlowsDataService) }, + mockProvider(FlowsDataService), + mockProvider(ResetAuthDataService), + mockProvider(LoggerService), { provide: DOCUMENT, useValue: { @@ -91,9 +88,9 @@ describe('ImplicitFlowCallbackHandlerService', () => { it('returns callbackContext if all params are good', waitForAsync(() => { spyOn(flowsDataService, 'isSilentRenewRunning').and.returnValue(true); const expectedCallbackContext = { - code: null, - refreshToken: null, - state: null, + code: '', + refreshToken: '', + state: '', sessionState: null, authResult: { anyHash: '' }, isRenewProcess: true, @@ -118,9 +115,9 @@ describe('ImplicitFlowCallbackHandlerService', () => { it('uses window location hash if no hash is passed', waitForAsync(() => { spyOn(flowsDataService, 'isSilentRenewRunning').and.returnValue(true); const expectedCallbackContext = { - code: null, - refreshToken: null, - state: null, + code: '', + refreshToken: '', + state: '', sessionState: null, authResult: { anyFakeHash: '' }, isRenewProcess: true, diff --git a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/implicit-flow-callback-handler.service.ts b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/implicit-flow-callback-handler.service.ts index a9aac2ad7..e88694c6d 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/implicit-flow-callback-handler.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/implicit-flow-callback-handler.service.ts @@ -43,10 +43,10 @@ export class ImplicitFlowCallbackHandlerService { return resultData; }, {}); - const callbackContext = { - code: null, - refreshToken: null, - state: null, + const callbackContext: CallbackContext = { + code: '', + refreshToken: '', + state: '', sessionState: null, authResult, isRenewProcess: isRenewProcessData, diff --git a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/refresh-session-callback-handler.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/refresh-session-callback-handler.service.spec.ts index ee17f6c89..9973dc3e2 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/refresh-session-callback-handler.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/refresh-session-callback-handler.service.spec.ts @@ -1,7 +1,8 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { AuthStateService } from '../../auth-state/auth-state.service'; import { LoggerService } from '../../logging/logger.service'; +import { CallbackContext } from '../callback-context'; import { FlowsDataService } from '../flows-data.service'; import { RefreshSessionCallbackHandlerService } from './refresh-session-callback-handler.service'; @@ -14,9 +15,9 @@ describe('RefreshSessionCallbackHandlerService', () => { TestBed.configureTestingModule({ providers: [ RefreshSessionCallbackHandlerService, - { provide: AuthStateService, useClass: mockClass(AuthStateService) }, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { provide: FlowsDataService, useClass: mockClass(FlowsDataService) }, + mockProvider(AuthStateService), + mockProvider(LoggerService), + mockProvider(FlowsDataService), ], }); }); @@ -43,7 +44,7 @@ describe('RefreshSessionCallbackHandlerService', () => { spyOn(authStateService, 'getIdToken').and.returnValue('henlo-legger'); const expectedCallbackContext = { - code: null, + code: '', refreshToken: 'henlo-furiend', state: 'state-data', sessionState: null, @@ -52,7 +53,7 @@ describe('RefreshSessionCallbackHandlerService', () => { jwtKeys: null, validationResult: null, existingIdToken: 'henlo-legger', - }; + } as CallbackContext; service .refreshSessionWithRefreshTokens({ configId: 'configId1' }) @@ -66,7 +67,7 @@ describe('RefreshSessionCallbackHandlerService', () => { flowsDataService, 'getExistingOrCreateAuthStateControl' ).and.returnValue('state-data'); - spyOn(authStateService, 'getRefreshToken').and.returnValue(null); + spyOn(authStateService, 'getRefreshToken').and.returnValue(''); spyOn(authStateService, 'getIdToken').and.returnValue('henlo-legger'); service diff --git a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/refresh-session-callback-handler.service.ts b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/refresh-session-callback-handler.service.ts index fc6c3b95b..dd667c31b 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/refresh-session-callback-handler.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/refresh-session-callback-handler.service.ts @@ -30,8 +30,8 @@ export class RefreshSessionCallbackHandlerService { const idToken = this.authStateService.getIdToken(config); if (refreshToken) { - const callbackContext = { - code: null, + const callbackContext: CallbackContext = { + code: '', refreshToken, state: stateData, sessionState: null, diff --git a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/refresh-token-callback-handler.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/refresh-token-callback-handler.service.spec.ts index 846ce5e61..ee421b330 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/refresh-token-callback-handler.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/refresh-token-callback-handler.service.spec.ts @@ -1,7 +1,7 @@ import { HttpErrorResponse, HttpHeaders } from '@angular/common/http'; import { TestBed, waitForAsync } from '@angular/core/testing'; import { of, throwError } from 'rxjs'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { createRetriableStream } from '../../../test/create-retriable-stream.helper'; import { DataService } from '../../api/data.service'; import { LoggerService } from '../../logging/logger.service'; @@ -19,13 +19,10 @@ describe('RefreshTokenCallbackHandlerService', () => { TestBed.configureTestingModule({ providers: [ RefreshTokenCallbackHandlerService, - { provide: UrlService, useClass: mockClass(UrlService) }, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { provide: DataService, useClass: mockClass(DataService) }, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, + mockProvider(UrlService), + mockProvider(LoggerService), + mockProvider(DataService), + mockProvider(StoragePersistenceService), ], }); }); @@ -53,7 +50,7 @@ describe('RefreshTokenCallbackHandlerService', () => { (service as any) .refreshTokensRequestTokens({} as CallbackContext) .subscribe({ - error: (err) => { + error: (err: any) => { expect(err).toBeTruthy(); }, }); diff --git a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/refresh-token-callback-handler.service.ts b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/refresh-token-callback-handler.service.ts index 8297f5b4b..1c1772a64 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/refresh-token-callback-handler.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/refresh-token-callback-handler.service.ts @@ -44,30 +44,33 @@ export class RefreshTokenCallbackHandlerService { customParamsRefresh ); - return this.dataService.post(tokenEndpoint, data, config, headers).pipe( - switchMap((response: AuthResult) => { - this.loggerService.logDebug( - config, - 'token refresh response: ', - response - ); - - response.state = callbackContext.state; - - callbackContext.authResult = response; - - return of(callbackContext); - }), - retryWhen((error) => this.handleRefreshRetry(error, config)), - catchError((error) => { - const { authority } = config; - const errorMessage = `OidcService code request ${authority}`; - - this.loggerService.logError(config, errorMessage, error); - - return throwError(() => new Error(errorMessage)); - }) - ); + return this.dataService + .post(tokenEndpoint, data, config, headers) + .pipe( + switchMap((response) => { + this.loggerService.logDebug( + config, + `token refresh response: ${response}` + ); + + if (response) { + response.state = callbackContext.state; + } + + callbackContext.authResult = response; + + return of(callbackContext); + }), + retryWhen((error) => this.handleRefreshRetry(error, config)), + catchError((error) => { + const { authority } = config; + const errorMessage = `OidcService code request ${authority}`; + + this.loggerService.logError(config, errorMessage, error); + + return throwError(() => new Error(errorMessage)); + }) + ); } private handleRefreshRetry( @@ -88,7 +91,7 @@ export class RefreshTokenCallbackHandlerService { this.loggerService.logWarning(config, errorMessage, error); - return timer(refreshTokenRetryInSeconds * 1000); + return timer((refreshTokenRetryInSeconds ?? 0) * 1000); } return throwError(() => error); diff --git a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/state-validation-callback-handler.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/state-validation-callback-handler.service.spec.ts index df0d7f758..eb09a14ce 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/state-validation-callback-handler.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/state-validation-callback-handler.service.spec.ts @@ -1,7 +1,7 @@ import { DOCUMENT } from '@angular/common'; import { TestBed, waitForAsync } from '@angular/core/testing'; import { of } from 'rxjs'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { AuthStateService } from '../../auth-state/auth-state.service'; import { LoggerService } from '../../logging/logger.service'; import { StateValidationResult } from '../../validation/state-validation-result'; @@ -22,16 +22,10 @@ describe('StateValidationCallbackHandlerService', () => { TestBed.configureTestingModule({ providers: [ StateValidationCallbackHandlerService, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { - provide: StateValidationService, - useClass: mockClass(StateValidationService), - }, - { provide: AuthStateService, useClass: mockClass(AuthStateService) }, - { - provide: ResetAuthDataService, - useClass: mockClass(ResetAuthDataService), - }, + mockProvider(LoggerService), + mockProvider(StateValidationService), + mockProvider(AuthStateService), + mockProvider(ResetAuthDataService), { provide: DOCUMENT, useValue: { diff --git a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/user-callback-handler.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/user-callback-handler.service.spec.ts index 8e02a4887..5696a6c9f 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/user-callback-handler.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/user-callback-handler.service.spec.ts @@ -1,11 +1,12 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { of } from 'rxjs'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { AuthStateService } from '../../auth-state/auth-state.service'; import { LoggerService } from '../../logging/logger.service'; import { UserService } from '../../user-data/user.service'; import { StateValidationResult } from '../../validation/state-validation-result'; import { ValidationResult } from '../../validation/validation-result'; +import { CallbackContext } from '../callback-context'; import { FlowsDataService } from '../flows-data.service'; import { ResetAuthDataService } from '../reset-auth-data.service'; import { UserCallbackHandlerService } from './user-callback-handler.service'; @@ -21,14 +22,11 @@ describe('UserCallbackHandlerService', () => { TestBed.configureTestingModule({ providers: [ UserCallbackHandlerService, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { provide: AuthStateService, useClass: mockClass(AuthStateService) }, - { provide: FlowsDataService, useClass: mockClass(FlowsDataService) }, - { provide: UserService, useClass: mockClass(UserService) }, - { - provide: ResetAuthDataService, - useClass: mockClass(ResetAuthDataService), - }, + mockProvider(LoggerService), + mockProvider(AuthStateService), + mockProvider(FlowsDataService), + mockProvider(UserService), + mockProvider(ResetAuthDataService), ], }); }); @@ -54,16 +52,16 @@ describe('UserCallbackHandlerService', () => { 'decoded' ); const callbackContext = { - code: null, - refreshToken: null, - state: null, + code: '', + refreshToken: '', + state: '', sessionState: null, authResult: { session_state: 'mystate' }, isRenewProcess: false, jwtKeys: null, validationResult: svr, - existingIdToken: null, - }; + existingIdToken: '', + } as CallbackContext; const allConfigs = [ { @@ -90,16 +88,16 @@ describe('UserCallbackHandlerService', () => { 'decoded' ); const callbackContext = { - code: null, - refreshToken: null, - state: null, + code: '', + refreshToken: '', + state: '', sessionState: null, authResult: { session_state: 'mystate' }, isRenewProcess: true, jwtKeys: null, validationResult: svr, existingIdToken: null, - }; + } as CallbackContext; const allConfigs = [ { configId: 'configId1', @@ -124,16 +122,16 @@ describe('UserCallbackHandlerService', () => { 'decoded' ); const callbackContext = { - code: null, + code: '', refreshToken: 'somerefreshtoken', - state: null, + state: '', sessionState: null, authResult: { session_state: 'mystate' }, isRenewProcess: false, jwtKeys: null, validationResult: svr, existingIdToken: null, - }; + } as CallbackContext; const allConfigs = [ { configId: 'configId1', @@ -153,16 +151,16 @@ describe('UserCallbackHandlerService', () => { it('does NOT call flowsDataService.setSessionState if autoUserInfo is false isRenewProcess is false, refreshToken has value, id_token is false', waitForAsync(() => { const svr = new StateValidationResult('accesstoken', '', true, ''); const callbackContext = { - code: null, + code: '', refreshToken: 'somerefreshtoken', - state: null, + state: '', sessionState: null, authResult: { session_state: 'mystate' }, isRenewProcess: false, jwtKeys: null, validationResult: svr, existingIdToken: null, - }; + } as CallbackContext; const allConfigs = [ { configId: 'configId1', @@ -188,16 +186,16 @@ describe('UserCallbackHandlerService', () => { 'decoded' ); const callbackContext = { - code: null, + code: '', refreshToken: 'somerefreshtoken', - state: null, + state: '', sessionState: null, authResult: { session_state: 'mystate' }, isRenewProcess: false, jwtKeys: null, validationResult: svr, existingIdToken: null, - }; + } as CallbackContext; const allConfigs = [ { @@ -231,16 +229,16 @@ describe('UserCallbackHandlerService', () => { 'decoded' ); const callbackContext = { - code: null, + code: '', refreshToken: 'somerefreshtoken', - state: null, + state: '', sessionState: null, authResult: { session_state: 'mystate' }, isRenewProcess: false, jwtKeys: null, validationResult: svr, existingIdToken: null, - }; + } as CallbackContext; const allConfigs = [ { @@ -277,16 +275,16 @@ describe('UserCallbackHandlerService', () => { ValidationResult.MaxOffsetExpired ); const callbackContext = { - code: null, + code: '', refreshToken: 'somerefreshtoken', - state: null, + state: '', sessionState: null, authResult: { session_state: 'mystate' }, isRenewProcess: false, jwtKeys: null, validationResult: svr, existingIdToken: null, - }; + } as CallbackContext; const allConfigs = [ { @@ -324,16 +322,16 @@ describe('UserCallbackHandlerService', () => { ValidationResult.MaxOffsetExpired ); const callbackContext = { - code: null, + code: '', refreshToken: '', // something falsy - state: null, + state: '', sessionState: null, authResult: { session_state: 'mystate' }, isRenewProcess: false, jwtKeys: null, validationResult: svr, existingIdToken: null, - }; + } as CallbackContext; const allConfigs = [ { @@ -367,16 +365,16 @@ describe('UserCallbackHandlerService', () => { ValidationResult.MaxOffsetExpired ); const callbackContext = { - code: null, + code: '', refreshToken: 'somerefreshtoken', - state: null, + state: '', sessionState: null, authResult: { session_state: 'mystate' }, isRenewProcess: false, jwtKeys: null, validationResult: svr, existingIdToken: null, - }; + } as CallbackContext; const allConfigs = [ { @@ -418,16 +416,16 @@ describe('UserCallbackHandlerService', () => { ValidationResult.MaxOffsetExpired ); const callbackContext = { - code: null, + code: '', refreshToken: 'somerefreshtoken', - state: null, + state: '', sessionState: null, authResult: { session_state: 'mystate' }, isRenewProcess: false, jwtKeys: null, validationResult: svr, existingIdToken: null, - }; + } as CallbackContext; const allConfigs = [ { diff --git a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/user-callback-handler.service.ts b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/user-callback-handler.service.ts index af4e88a80..5ca190d4b 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/user-callback-handler.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/callback-handling/user-callback-handler.service.ts @@ -33,7 +33,7 @@ export class UserCallbackHandlerService { if (!autoUserInfo) { if (!isRenewProcess || renewUserInfoAfterTokenRenew) { // userData is set to the id_token decoded, auto get user data set to false - if (validationResult.decodedIdToken) { + if (validationResult?.decodedIdToken) { this.userService.setUserDataToStore( validationResult.decodedIdToken, configuration, @@ -44,7 +44,7 @@ export class UserCallbackHandlerService { if (!isRenewProcess && !refreshToken) { this.flowsDataService.setSessionState( - authResult.session_state, + authResult?.session_state, configuration ); } @@ -59,15 +59,15 @@ export class UserCallbackHandlerService { configuration, allConfigs, isRenewProcess, - validationResult.idToken, - validationResult.decodedIdToken + validationResult?.idToken, + validationResult?.decodedIdToken ) .pipe( switchMap((userData) => { if (!!userData) { if (!refreshToken) { this.flowsDataService.setSessionState( - authResult.session_state, + authResult?.session_state, configuration ); } @@ -99,9 +99,13 @@ export class UserCallbackHandlerService { } private publishAuthState( - stateValidationResult: StateValidationResult, + stateValidationResult: StateValidationResult | null, isRenewProcess: boolean ): void { + if (!stateValidationResult) { + return; + } + this.authStateService.updateAndPublishAuthState({ isAuthenticated: true, validationResult: stateValidationResult.state, @@ -110,9 +114,13 @@ export class UserCallbackHandlerService { } private publishUnauthenticatedState( - stateValidationResult: StateValidationResult, + stateValidationResult: StateValidationResult | null, isRenewProcess: boolean ): void { + if (!stateValidationResult) { + return; + } + this.authStateService.updateAndPublishAuthState({ isAuthenticated: false, validationResult: stateValidationResult.state, diff --git a/projects/angular-auth-oidc-client/src/lib/flows/flows-data.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/flows/flows-data.service.spec.ts index 353ef9ff7..dc8e25868 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/flows-data.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/flows-data.service.spec.ts @@ -1,5 +1,5 @@ import { TestBed } from '@angular/core/testing'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { LoggerService } from '../logging/logger.service'; import { StoragePersistenceService } from '../storage/storage-persistence.service'; import { CryptoService } from '../utils/crypto/crypto.service'; @@ -16,11 +16,8 @@ describe('Flows Data Service', () => { FlowsDataService, RandomService, CryptoService, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, + mockProvider(LoggerService), + mockProvider(StoragePersistenceService), ], }); }); diff --git a/projects/angular-auth-oidc-client/src/lib/flows/flows-data.service.ts b/projects/angular-auth-oidc-client/src/lib/flows/flows-data.service.ts index fd5264e0c..999c784bf 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/flows-data.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/flows-data.service.ts @@ -26,7 +26,11 @@ export class FlowsDataService { this.storagePersistenceService.write('authNonce', nonce, configuration); } - getAuthStateControl(configuration: OpenIdConfiguration): any { + getAuthStateControl(configuration: OpenIdConfiguration | null): string { + if (!configuration) { + return ''; + } + return this.storagePersistenceService.read( 'authStateControl', configuration @@ -35,8 +39,12 @@ export class FlowsDataService { setAuthStateControl( authStateControl: string, - configuration: OpenIdConfiguration + configuration: OpenIdConfiguration | null ): boolean { + if (!configuration) { + return false; + } + return this.storagePersistenceService.write( 'authStateControl', authStateControl, @@ -121,7 +129,11 @@ export class FlowsDataService { return false; } - const timeOutInMilliseconds = silentRenewTimeoutInSeconds * 1000; + if (storageObject.state === 'not-running') { + return false; + } + + const timeOutInMilliseconds = (silentRenewTimeoutInSeconds ?? 0) * 1000; const dateOfLaunchedProcessUtc = Date.parse( storageObject.dateOfLaunchedProcessUtc ); @@ -158,7 +170,11 @@ export class FlowsDataService { ); } - resetSilentRenewRunning(configuration: OpenIdConfiguration): void { + resetSilentRenewRunning(configuration: OpenIdConfiguration | null): void { + if (!configuration) { + return; + } + this.storagePersistenceService.write( 'storageSilentRenewRunning', '', @@ -175,7 +191,10 @@ export class FlowsDataService { ); if (!storageEntry) { - return null; + return { + dateOfLaunchedProcessUtc: '', + state: 'not-running', + }; } return JSON.parse(storageEntry); diff --git a/projects/angular-auth-oidc-client/src/lib/flows/flows.models.ts b/projects/angular-auth-oidc-client/src/lib/flows/flows.models.ts index 996b587ea..f1089c83e 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/flows.models.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/flows.models.ts @@ -3,4 +3,4 @@ export interface SilentRenewRunning { dateOfLaunchedProcessUtc: string; } -export type SilentRenewRunningState = 'running'; +export type SilentRenewRunningState = 'running' | 'not-running'; diff --git a/projects/angular-auth-oidc-client/src/lib/flows/flows.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/flows/flows.service.spec.ts index 5e0500d34..34c33cef2 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/flows.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/flows.service.spec.ts @@ -1,6 +1,6 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { of } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { CallbackContext } from './callback-context'; import { CodeFlowCallbackHandlerService } from './callback-handling/code-flow-callback-handler.service'; import { HistoryJwtKeysCallbackHandlerService } from './callback-handling/history-jwt-keys-callback-handler.service'; @@ -25,34 +25,13 @@ describe('Flows Service', () => { TestBed.configureTestingModule({ providers: [ FlowsService, - { - provide: CodeFlowCallbackHandlerService, - useClass: mockClass(CodeFlowCallbackHandlerService), - }, - { - provide: ImplicitFlowCallbackHandlerService, - useClass: mockClass(ImplicitFlowCallbackHandlerService), - }, - { - provide: HistoryJwtKeysCallbackHandlerService, - useClass: mockClass(HistoryJwtKeysCallbackHandlerService), - }, - { - provide: UserCallbackHandlerService, - useClass: mockClass(UserCallbackHandlerService), - }, - { - provide: StateValidationCallbackHandlerService, - useClass: mockClass(StateValidationCallbackHandlerService), - }, - { - provide: RefreshSessionCallbackHandlerService, - useClass: mockClass(RefreshSessionCallbackHandlerService), - }, - { - provide: RefreshTokenCallbackHandlerService, - useClass: mockClass(RefreshTokenCallbackHandlerService), - }, + mockProvider(CodeFlowCallbackHandlerService), + mockProvider(ImplicitFlowCallbackHandlerService), + mockProvider(HistoryJwtKeysCallbackHandlerService), + mockProvider(UserCallbackHandlerService), + mockProvider(StateValidationCallbackHandlerService), + mockProvider(RefreshSessionCallbackHandlerService), + mockProvider(RefreshTokenCallbackHandlerService), ], }); }); @@ -89,23 +68,23 @@ describe('Flows Service', () => { const codeFlowCallbackSpy = spyOn( codeFlowCallbackHandlerService, 'codeFlowCallback' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const codeFlowCodeRequestSpy = spyOn( codeFlowCallbackHandlerService, 'codeFlowCodeRequest' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const callbackHistoryAndResetJwtKeysSpy = spyOn( historyJwtKeysCallbackHandlerService, 'callbackHistoryAndResetJwtKeys' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const callbackStateValidationSpy = spyOn( stateValidationCallbackHandlerService, 'callbackStateValidation' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const callbackUserSpy = spyOn( userCallbackHandlerService, 'callbackUser' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const allConfigs = [ { configId: 'configId1', @@ -115,7 +94,7 @@ describe('Flows Service', () => { service .processCodeFlowCallback('some-url1234', allConfigs[0], allConfigs) .subscribe((value) => { - expect(value).toBeNull(); + expect(value).toEqual({} as CallbackContext); expect(codeFlowCallbackSpy).toHaveBeenCalledOnceWith( 'some-url1234', allConfigs[0] @@ -133,19 +112,19 @@ describe('Flows Service', () => { const codeFlowCodeRequestSpy = spyOn( codeFlowCallbackHandlerService, 'codeFlowCodeRequest' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const callbackHistoryAndResetJwtKeysSpy = spyOn( historyJwtKeysCallbackHandlerService, 'callbackHistoryAndResetJwtKeys' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const callbackStateValidationSpy = spyOn( stateValidationCallbackHandlerService, 'callbackStateValidation' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const callbackUserSpy = spyOn( userCallbackHandlerService, 'callbackUser' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const allConfigs = [ { configId: 'configId1', @@ -159,7 +138,7 @@ describe('Flows Service', () => { allConfigs ) .subscribe((value) => { - expect(value).toBeNull(); + expect(value).toEqual({} as CallbackContext); expect(codeFlowCodeRequestSpy).toHaveBeenCalled(); expect(callbackHistoryAndResetJwtKeysSpy).toHaveBeenCalled(); expect(callbackStateValidationSpy).toHaveBeenCalled(); @@ -173,19 +152,19 @@ describe('Flows Service', () => { const implicitFlowCallbackSpy = spyOn( implicitFlowCallbackHandlerService, 'implicitFlowCallback' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const callbackHistoryAndResetJwtKeysSpy = spyOn( historyJwtKeysCallbackHandlerService, 'callbackHistoryAndResetJwtKeys' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const callbackStateValidationSpy = spyOn( stateValidationCallbackHandlerService, 'callbackStateValidation' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const callbackUserSpy = spyOn( userCallbackHandlerService, 'callbackUser' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const allConfigs = [ { configId: 'configId1', @@ -195,7 +174,7 @@ describe('Flows Service', () => { service .processImplicitFlowCallback(allConfigs[0], allConfigs, 'any-hash') .subscribe((value) => { - expect(value).toBeNull(); + expect(value).toEqual({} as CallbackContext); expect(implicitFlowCallbackSpy).toHaveBeenCalled(); expect(callbackHistoryAndResetJwtKeysSpy).toHaveBeenCalled(); expect(callbackStateValidationSpy).toHaveBeenCalled(); @@ -209,23 +188,23 @@ describe('Flows Service', () => { const refreshSessionWithRefreshTokensSpy = spyOn( refreshSessionCallbackHandlerService, 'refreshSessionWithRefreshTokens' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const refreshTokensRequestTokensSpy = spyOn( refreshTokenCallbackHandlerService, 'refreshTokensRequestTokens' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const callbackHistoryAndResetJwtKeysSpy = spyOn( historyJwtKeysCallbackHandlerService, 'callbackHistoryAndResetJwtKeys' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const callbackStateValidationSpy = spyOn( stateValidationCallbackHandlerService, 'callbackStateValidation' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const callbackUserSpy = spyOn( userCallbackHandlerService, 'callbackUser' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const allConfigs = [ { configId: 'configId1', @@ -235,7 +214,7 @@ describe('Flows Service', () => { service .processRefreshToken(allConfigs[0], allConfigs) .subscribe((value) => { - expect(value).toBeNull(); + expect(value).toEqual({} as CallbackContext); expect(refreshSessionWithRefreshTokensSpy).toHaveBeenCalled(); expect(refreshTokensRequestTokensSpy).toHaveBeenCalled(); expect(callbackHistoryAndResetJwtKeysSpy).toHaveBeenCalled(); diff --git a/projects/angular-auth-oidc-client/src/lib/flows/random/random.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/flows/random/random.service.spec.ts index fd004fbae..44f6aa6ab 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/random/random.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/random/random.service.spec.ts @@ -1,5 +1,5 @@ import { TestBed } from '@angular/core/testing'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { LoggerService } from '../../logging/logger.service'; import { CryptoService } from '../../utils/crypto/crypto.service'; import { RandomService } from './random.service'; @@ -9,11 +9,7 @@ describe('RandomService Tests', () => { beforeEach(() => { TestBed.configureTestingModule({ - providers: [ - RandomService, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - CryptoService, - ], + providers: [RandomService, mockProvider(LoggerService), CryptoService], }); }); diff --git a/projects/angular-auth-oidc-client/src/lib/flows/random/random.service.ts b/projects/angular-auth-oidc-client/src/lib/flows/random/random.service.ts index 0ea5d9685..34a83fca0 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/random/random.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/random/random.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; +import { OpenIdConfiguration } from '../../config/openid-configuration'; import { LoggerService } from '../../logging/logger.service'; import { CryptoService } from '../../utils/crypto/crypto.service'; -import { OpenIdConfiguration } from '../../config/openid-configuration'; @Injectable({ providedIn: 'root' }) export class RandomService { @@ -37,7 +37,7 @@ export class RandomService { return Array.from(arr, this.toHex).join('') + this.randomString(7); } - private toHex(dec): string { + private toHex(dec: number): string { return ('0' + dec.toString(16)).substr(-2); } diff --git a/projects/angular-auth-oidc-client/src/lib/flows/reset-auth-data.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/flows/reset-auth-data.service.spec.ts index c62b5a998..b19b2cfb1 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/reset-auth-data.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/reset-auth-data.service.spec.ts @@ -1,5 +1,5 @@ import { TestBed } from '@angular/core/testing'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { AuthStateService } from '../auth-state/auth-state.service'; import { LoggerService } from '../logging/logger.service'; import { UserService } from '../user-data/user.service'; @@ -16,10 +16,10 @@ describe('ResetAuthDataService', () => { TestBed.configureTestingModule({ providers: [ ResetAuthDataService, - { provide: AuthStateService, useClass: mockClass(AuthStateService) }, - { provide: FlowsDataService, useClass: mockClass(FlowsDataService) }, - { provide: UserService, useClass: mockClass(UserService) }, - { provide: LoggerService, useClass: mockClass(LoggerService) }, + mockProvider(AuthStateService), + mockProvider(FlowsDataService), + mockProvider(UserService), + mockProvider(LoggerService), ], }); }); diff --git a/projects/angular-auth-oidc-client/src/lib/flows/reset-auth-data.service.ts b/projects/angular-auth-oidc-client/src/lib/flows/reset-auth-data.service.ts index 27d476e8d..d43c9fdc4 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/reset-auth-data.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/reset-auth-data.service.ts @@ -15,9 +15,13 @@ export class ResetAuthDataService { ) {} resetAuthorizationData( - currentConfiguration: OpenIdConfiguration, + currentConfiguration: OpenIdConfiguration | null, allConfigs: OpenIdConfiguration[] ): void { + if (!currentConfiguration) { + return; + } + this.userService.resetUserDataInStore(currentConfiguration, allConfigs); this.flowsDataService.resetStorageFlowData(currentConfiguration); this.authStateService.setUnauthenticatedAndFireEvent( diff --git a/projects/angular-auth-oidc-client/src/lib/flows/signin-key-data.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/flows/signin-key-data.service.spec.ts index edc8acc9c..08fb0f4c5 100644 --- a/projects/angular-auth-oidc-client/src/lib/flows/signin-key-data.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/flows/signin-key-data.service.spec.ts @@ -1,7 +1,7 @@ import { HttpResponse } from '@angular/common/http'; import { TestBed, waitForAsync } from '@angular/core/testing'; import { isObservable, of, throwError } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { createRetriableStream } from '../../test/create-retriable-stream.helper'; import { DataService } from '../api/data.service'; import { LoggerService } from '../logging/logger.service'; @@ -34,12 +34,9 @@ describe('Signin Key Data Service', () => { TestBed.configureTestingModule({ providers: [ SigninKeyDataService, - { provide: DataService, useClass: mockClass(DataService) }, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, + mockProvider(DataService), + mockProvider(LoggerService), + mockProvider(StoragePersistenceService), ], }); }); diff --git a/projects/angular-auth-oidc-client/src/lib/iframe/check-session.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/iframe/check-session.service.spec.ts index 462d2539c..db4db75be 100644 --- a/projects/angular-auth-oidc-client/src/lib/iframe/check-session.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/iframe/check-session.service.spec.ts @@ -1,14 +1,14 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { of } from 'rxjs'; import { skip } from 'rxjs/operators'; -import { mockClass } from '../../test/auto-mock'; +import { mockAbstractProvider, mockProvider } from '../../test/auto-mock'; import { LoggerService } from '../logging/logger.service'; import { OidcSecurityService } from '../oidc.security.service'; import { PublicEventsService } from '../public-events/public-events.service'; import { AbstractSecurityStorage } from '../storage/abstract-security-storage'; +import { DefaultSessionStorageService } from '../storage/default-sessionstorage.service'; import { StoragePersistenceService } from '../storage/storage-persistence.service'; import { PlatformProvider } from '../utils/platform-provider/platform.provider'; -import { DefaultSessionStorageService } from '../storage/default-sessionstorage.service'; import { CheckSessionService } from './check-session.service'; import { IFrameService } from './existing-iframe.service'; @@ -25,16 +25,13 @@ describe('CheckSessionService', () => { OidcSecurityService, IFrameService, PublicEventsService, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { - provide: AbstractSecurityStorage, - useClass: mockClass(DefaultSessionStorageService), - }, - { provide: PlatformProvider, useClass: mockClass(PlatformProvider) }, + mockProvider(StoragePersistenceService), + mockProvider(LoggerService), + mockProvider(PlatformProvider), + mockAbstractProvider( + AbstractSecurityStorage, + DefaultSessionStorageService + ), ], }); }); @@ -52,7 +49,7 @@ describe('CheckSessionService', () => { ); if (iFrameIdwhichshouldneverexist) { - iFrameIdwhichshouldneverexist.parentNode.removeChild( + iFrameIdwhichshouldneverexist.parentNode?.removeChild( iFrameIdwhichshouldneverexist ); } @@ -61,7 +58,7 @@ describe('CheckSessionService', () => { ); if (myiFrameForCheckSession) { - myiFrameForCheckSession.parentNode.removeChild(myiFrameForCheckSession); + myiFrameForCheckSession.parentNode?.removeChild(myiFrameForCheckSession); } }); @@ -301,7 +298,7 @@ describe('CheckSessionService', () => { serviceAsAny.lastIFrameRefresh = lastRefresh; serviceAsAny.iframeRefreshInterval = lastRefresh; - serviceAsAny.init().subscribe((result) => { + serviceAsAny.init().subscribe((result: any) => { expect(result).toBeUndefined(); }); })); diff --git a/projects/angular-auth-oidc-client/src/lib/iframe/check-session.service.ts b/projects/angular-auth-oidc-client/src/lib/iframe/check-session.service.ts index 48a9b08f5..791bbcf5a 100644 --- a/projects/angular-auth-oidc-client/src/lib/iframe/check-session.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/iframe/check-session.service.ts @@ -1,14 +1,13 @@ import { DOCUMENT } from '@angular/common'; -import { Inject, Injectable, NgZone } from '@angular/core'; +import { Inject, Injectable, NgZone, OnDestroy } from '@angular/core'; import { BehaviorSubject, Observable, of } from 'rxjs'; import { take } from 'rxjs/operators'; +import { OpenIdConfiguration } from '../config/openid-configuration'; import { LoggerService } from '../logging/logger.service'; import { EventTypes } from '../public-events/event-types'; import { PublicEventsService } from '../public-events/public-events.service'; import { StoragePersistenceService } from '../storage/storage-persistence.service'; -import { OpenIdConfiguration } from '../config/openid-configuration'; import { IFrameService } from './existing-iframe.service'; -import { OnDestroy } from '@angular/core'; const IFRAME_FOR_CHECK_SESSION_IDENTIFIER = 'myiFrameForCheckSession'; @@ -49,17 +48,21 @@ export class CheckSessionService implements OnDestroy { ngOnDestroy(): void { this.stop(); - this.document.defaultView.removeEventListener( - 'message', - this.iframeMessageEventListener, - false - ); + const windowAsDefaultView = this.document.defaultView; + + if (windowAsDefaultView) { + windowAsDefaultView.removeEventListener( + 'message', + this.iframeMessageEventListener, + false + ); + } } isCheckSessionConfigured(configuration: OpenIdConfiguration): boolean { const { startCheckSession } = configuration; - return startCheckSession; + return Boolean(startCheckSession); } start(configuration: OpenIdConfiguration): void { @@ -84,10 +87,10 @@ export class CheckSessionService implements OnDestroy { serverStateChanged(configuration: OpenIdConfiguration): boolean { const { startCheckSession } = configuration; - return startCheckSession && this.checkSessionReceived; + return Boolean(startCheckSession) && this.checkSessionReceived; } - getExistingIframe(): HTMLIFrameElement { + getExistingIframe(): HTMLIFrameElement | null { return this.iFrameService.getExistingIFrame( IFRAME_FOR_CHECK_SESSION_IDENTIFIER ); @@ -119,16 +122,24 @@ export class CheckSessionService implements OnDestroy { // this is done even if iframe exists for HMR to work, since iframe exists on service init this.bindMessageEventToIframe(configuration); const checkSessionIframe = authWellKnownEndPoints.checkSessionIframe; + const contentWindow = existingIframe.contentWindow; - if (checkSessionIframe) { - existingIframe.contentWindow.location.replace(checkSessionIframe); - } else { + if (!checkSessionIframe) { this.loggerService.logWarning( configuration, 'CheckSession - init check session: checkSessionIframe is not configured to run' ); } + if (!contentWindow) { + this.loggerService.logWarning( + configuration, + 'CheckSession - init check session: IFrame contentWindow does not exist' + ); + } else { + contentWindow.location.replace(checkSessionIframe); + } + return new Observable((observer) => { existingIframe.onload = (): void => { this.lastIFrameRefresh = Date.now(); @@ -139,7 +150,7 @@ export class CheckSessionService implements OnDestroy { } private pollServerSession( - clientId: string, + clientId: string | undefined, configuration: OpenIdConfiguration ): void { this.outstandingMessages = 0; @@ -163,14 +174,19 @@ export class CheckSessionService implements OnDestroy { 'authWellKnownEndPoints', configuration ); + const contentWindow = existingIframe.contentWindow; - if (sessionState && authWellKnownEndPoints?.checkSessionIframe) { + if ( + sessionState && + authWellKnownEndPoints?.checkSessionIframe && + contentWindow + ) { const iframeOrigin = new URL( authWellKnownEndPoints.checkSessionIframe )?.origin; this.outstandingMessages++; - existingIframe.contentWindow.postMessage( + contentWindow.postMessage( clientId + ' ' + sessionState, iframeOrigin ); @@ -264,11 +280,16 @@ export class CheckSessionService implements OnDestroy { this, configuration ); - this.document.defaultView.addEventListener( - 'message', - this.iframeMessageEventListener, - false - ); + + const defaultView = this.document.defaultView; + + if (defaultView) { + defaultView.addEventListener( + 'message', + this.iframeMessageEventListener, + false + ); + } } private getOrCreateIframe( diff --git a/projects/angular-auth-oidc-client/src/lib/iframe/existing-iframe.service.ts b/projects/angular-auth-oidc-client/src/lib/iframe/existing-iframe.service.ts index 1f8053456..bf6f74f4f 100644 --- a/projects/angular-auth-oidc-client/src/lib/iframe/existing-iframe.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/iframe/existing-iframe.service.ts @@ -46,7 +46,7 @@ export class IFrameService { ): HTMLIFrameElement | null { try { const iFrameElement = - this.document.defaultView.parent.document.getElementById(identifier); + this.document.defaultView?.parent.document.getElementById(identifier); if (this.isIFrameElement(iFrameElement)) { return iFrameElement; @@ -69,7 +69,7 @@ export class IFrameService { } private isIFrameElement( - element: HTMLElement | null + element: HTMLElement | null | undefined ): element is HTMLIFrameElement { return !!element && element instanceof HTMLIFrameElement; } diff --git a/projects/angular-auth-oidc-client/src/lib/iframe/refresh-session-iframe.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/iframe/refresh-session-iframe.service.spec.ts index a667ddac9..1dd2fcafb 100644 --- a/projects/angular-auth-oidc-client/src/lib/iframe/refresh-session-iframe.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/iframe/refresh-session-iframe.service.spec.ts @@ -1,6 +1,6 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { of } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { LoggerService } from '../logging/logger.service'; import { UrlService } from '../utils/url/url.service'; import { RefreshSessionIframeService } from './refresh-session-iframe.service'; @@ -14,12 +14,9 @@ describe('RefreshSessionIframeService ', () => { TestBed.configureTestingModule({ providers: [ RefreshSessionIframeService, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { provide: UrlService, useClass: mockClass(UrlService) }, - { - provide: SilentRenewService, - useClass: mockClass(SilentRenewService), - }, + mockProvider(SilentRenewService), + mockProvider(LoggerService), + mockProvider(UrlService), ], }); }); diff --git a/projects/angular-auth-oidc-client/src/lib/iframe/refresh-session-iframe.service.ts b/projects/angular-auth-oidc-client/src/lib/iframe/refresh-session-iframe.service.ts index b468ca3a7..eb473a725 100644 --- a/projects/angular-auth-oidc-client/src/lib/iframe/refresh-session-iframe.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/iframe/refresh-session-iframe.service.ts @@ -45,7 +45,7 @@ export class RefreshSessionIframeService { } private sendAuthorizeRequestUsingSilentRenew( - url: string, + url: string | null, config: OpenIdConfiguration, allConfigs: OpenIdConfiguration[] ): Observable { @@ -54,7 +54,7 @@ export class RefreshSessionIframeService { this.initSilentRenewRequest(config, allConfigs); this.loggerService.logDebug( config, - 'sendAuthorizeRequestUsingSilentRenew for URL:' + url + `sendAuthorizeRequestUsingSilentRenew for URL: ${url}` ); return new Observable((observer) => { @@ -69,7 +69,7 @@ export class RefreshSessionIframeService { }; sessionIframe.addEventListener('load', onLoadHandler); - sessionIframe.contentWindow.location.replace(url); + sessionIframe.contentWindow?.location.replace(url ?? ''); }); } @@ -96,7 +96,7 @@ export class RefreshSessionIframeService { this.silentRenewService.silentRenewEventHandler(e, config, allConfigs) ); - this.document.defaultView.dispatchEvent( + this.document.defaultView?.dispatchEvent( new CustomEvent('oidc-silent-renew-init', { detail: instanceId, }) diff --git a/projects/angular-auth-oidc-client/src/lib/iframe/silent-renew.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/iframe/silent-renew.service.spec.ts index 7ebfd10c6..da0d92f3b 100644 --- a/projects/angular-auth-oidc-client/src/lib/iframe/silent-renew.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/iframe/silent-renew.service.spec.ts @@ -1,6 +1,6 @@ import { fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing'; import { Observable, of, throwError } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { AuthStateService } from '../auth-state/auth-state.service'; import { ImplicitFlowCallbackService } from '../callback/implicit-flow-callback.service'; import { IntervalService } from '../callback/interval.service'; @@ -31,20 +31,14 @@ describe('SilentRenewService ', () => { providers: [ SilentRenewService, IFrameService, - { provide: FlowsService, useClass: mockClass(FlowsService) }, - { - provide: ResetAuthDataService, - useClass: mockClass(ResetAuthDataService), - }, - { provide: FlowsDataService, useClass: mockClass(FlowsDataService) }, - { provide: AuthStateService, useClass: mockClass(AuthStateService) }, - { provide: LoggerService, useClass: mockClass(LoggerService) }, + mockProvider(FlowsService), + mockProvider(ResetAuthDataService), + mockProvider(FlowsDataService), + mockProvider(AuthStateService), + mockProvider(LoggerService), + mockProvider(ImplicitFlowCallbackService), + mockProvider(IntervalService), FlowHelper, - { - provide: ImplicitFlowCallbackService, - useClass: mockClass(ImplicitFlowCallbackService), - }, - IntervalService, ], }); }); @@ -139,10 +133,10 @@ describe('SilentRenewService ', () => { const spy = spyOn( flowsService, 'processSilentRenewCodeFlowCallback' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const expectedContext = { code: 'some-code', - refreshToken: null, + refreshToken: '', state: 'some-state', sessionState: 'some-session-state', authResult: null, @@ -150,7 +144,7 @@ describe('SilentRenewService ', () => { jwtKeys: null, validationResult: null, existingIdToken: null, - }; + } as CallbackContext; const url = 'url-part-1'; const urlParts = 'code=some-code&state=some-state&session_state=some-session-state'; @@ -173,7 +167,7 @@ describe('SilentRenewService ', () => { const spy = spyOn( flowsService, 'processSilentRenewCodeFlowCallback' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const authStateServiceSpy = spyOn( authStateService, 'updateAndPublishAuthState' @@ -223,7 +217,7 @@ describe('SilentRenewService ', () => { spyOn( implicitFlowCallbackService, 'authenticatedImplicitFlowCallback' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const eventData = { detail: null } as CustomEvent; const allConfigs = [{ configId: 'configId1' }]; @@ -244,7 +238,7 @@ describe('SilentRenewService ', () => { const authorizedImplicitFlowCallbackSpy = spyOn( implicitFlowCallbackService, 'authenticatedImplicitFlowCallback' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const eventData = { detail: 'detail' } as CustomEvent; const allConfigs = [{ configId: 'configId1' }]; @@ -267,7 +261,7 @@ describe('SilentRenewService ', () => { const codeFlowCallbackSilentRenewIframe = spyOn( silentRenewService, 'codeFlowCallbackSilentRenewIframe' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const eventData = { detail: 'detail?detail2' } as CustomEvent; const allConfigs = [{ configId: 'configId1' }]; @@ -289,7 +283,7 @@ describe('SilentRenewService ', () => { const codeFlowCallbackSilentRenewIframe = spyOn( silentRenewService, 'codeFlowCallbackSilentRenewIframe' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as CallbackContext)); const eventData = { detail: 'detail?detail2' } as CustomEvent; const allConfigs = [{ configId: 'configId1' }]; diff --git a/projects/angular-auth-oidc-client/src/lib/iframe/silent-renew.service.ts b/projects/angular-auth-oidc-client/src/lib/iframe/silent-renew.service.ts index 74e4a77ac..1c0941c49 100644 --- a/projects/angular-auth-oidc-client/src/lib/iframe/silent-renew.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/iframe/silent-renew.service.ts @@ -5,6 +5,7 @@ import { catchError } from 'rxjs/operators'; import { AuthStateService } from '../auth-state/auth-state.service'; import { ImplicitFlowCallbackService } from '../callback/implicit-flow-callback.service'; import { IntervalService } from '../callback/interval.service'; +import { OpenIdConfiguration } from '../config/openid-configuration'; import { CallbackContext } from '../flows/callback-context'; import { FlowsDataService } from '../flows/flows-data.service'; import { FlowsService } from '../flows/flows.service'; @@ -12,7 +13,6 @@ import { ResetAuthDataService } from '../flows/reset-auth-data.service'; import { LoggerService } from '../logging/logger.service'; import { FlowHelper } from '../utils/flowHelper/flow-helper.service'; import { ValidationResult } from '../validation/validation-result'; -import { OpenIdConfiguration } from '../config/openid-configuration'; import { IFrameService } from './existing-iframe.service'; const IFRAME_FOR_SILENT_RENEW_IDENTIFIER = 'myiFrameForSilentRenew'; @@ -20,9 +20,9 @@ const IFRAME_FOR_SILENT_RENEW_IDENTIFIER = 'myiFrameForSilentRenew'; @Injectable({ providedIn: 'root' }) export class SilentRenewService { private readonly refreshSessionWithIFrameCompletedInternal$ = - new Subject(); + new Subject(); - get refreshSessionWithIFrameCompleted$(): Observable { + get refreshSessionWithIFrameCompleted$(): Observable { return this.refreshSessionWithIFrameCompletedInternal$.asObservable(); } @@ -54,7 +54,7 @@ export class SilentRenewService { isSilentRenewConfigured(configuration: OpenIdConfiguration): boolean { const { useRefreshToken, silentRenew } = configuration; - return !useRefreshToken && silentRenew; + return !useRefreshToken && Boolean(silentRenew); } codeFlowCallbackSilentRenewIframe( @@ -66,9 +66,9 @@ export class SilentRenewService { fromString: urlParts[1], }); - const error = params.get('error'); + const errorParam = params.get('error'); - if (error) { + if (errorParam) { this.authStateService.updateAndPublishAuthState({ isAuthenticated: false, validationResult: ValidationResult.LoginRequired, @@ -78,16 +78,16 @@ export class SilentRenewService { this.flowsDataService.setNonce('', config); this.intervalService.stopPeriodicTokenCheck(); - return throwError(() => new Error(error)); + return throwError(() => new Error(errorParam)); } - const code = params.get('code'); - const state = params.get('state'); + const code = params.get('code') ?? ''; + const state = params.get('state') ?? ''; const sessionState = params.get('session_state'); - const callbackContext = { + const callbackContext: CallbackContext = { code, - refreshToken: null, + refreshToken: '', state, sessionState, authResult: null, @@ -100,7 +100,7 @@ export class SilentRenewService { return this.flowsService .processSilentRenewCodeFlowCallback(callbackContext, config, allConfigs) .pipe( - catchError(() => { + catchError((error) => { this.intervalService.stopPeriodicTokenCheck(); this.resetAuthDataService.resetAuthorizationData(config, allConfigs); @@ -152,7 +152,7 @@ export class SilentRenewService { }); } - private getExistingIframe(): HTMLIFrameElement { + private getExistingIframe(): HTMLIFrameElement | null { return this.iFrameService.getExistingIFrame( IFRAME_FOR_SILENT_RENEW_IDENTIFIER ); diff --git a/projects/angular-auth-oidc-client/src/lib/interceptor/auth.interceptor.spec.ts b/projects/angular-auth-oidc-client/src/lib/interceptor/auth.interceptor.spec.ts index 13a5b46e9..8ed0f6a74 100644 --- a/projects/angular-auth-oidc-client/src/lib/interceptor/auth.interceptor.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/interceptor/auth.interceptor.spec.ts @@ -1,6 +1,6 @@ import { - HttpClient, HTTP_INTERCEPTORS, + HttpClient, provideHttpClient, withInterceptors, } from '@angular/common/http'; @@ -10,11 +10,11 @@ import { provideHttpClientTesting, } from '@angular/common/http/testing'; import { TestBed, waitForAsync } from '@angular/core/testing'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { AuthStateService } from '../auth-state/auth-state.service'; import { ConfigurationService } from '../config/config.service'; import { LoggerService } from '../logging/logger.service'; -import { authInterceptor, AuthInterceptor } from './auth.interceptor'; +import { AuthInterceptor, authInterceptor } from './auth.interceptor'; import { ClosestMatchingRouteService } from './closest-matching-route.service'; describe(`AuthHttpInterceptor`, () => { @@ -35,15 +35,9 @@ describe(`AuthHttpInterceptor`, () => { useClass: AuthInterceptor, multi: true, }, - { provide: AuthStateService, useClass: mockClass(AuthStateService) }, - { - provide: LoggerService, - useClass: mockClass(LoggerService), - }, - { - provide: ConfigurationService, - useClass: mockClass(ConfigurationService), - }, + mockProvider(AuthStateService), + mockProvider(LoggerService), + mockProvider(ConfigurationService), ], }); @@ -68,15 +62,9 @@ describe(`AuthHttpInterceptor`, () => { ClosestMatchingRouteService, provideHttpClient(withInterceptors([authInterceptor()])), provideHttpClientTesting(), - { provide: AuthStateService, useClass: mockClass(AuthStateService) }, - { - provide: LoggerService, - useClass: mockClass(LoggerService), - }, - { - provide: ConfigurationService, - useClass: mockClass(ConfigurationService), - }, + mockProvider(AuthStateService), + mockProvider(LoggerService), + mockProvider(ConfigurationService), ], }); diff --git a/projects/angular-auth-oidc-client/src/lib/interceptor/auth.interceptor.ts b/projects/angular-auth-oidc-client/src/lib/interceptor/auth.interceptor.ts index b53aa4b1c..42a63adf1 100644 --- a/projects/angular-auth-oidc-client/src/lib/interceptor/auth.interceptor.ts +++ b/projects/angular-auth-oidc-client/src/lib/interceptor/auth.interceptor.ts @@ -11,6 +11,7 @@ import { Observable } from 'rxjs'; import { AuthStateService } from '../auth-state/auth-state.service'; import { ConfigurationService } from '../config/config.service'; import { LoggerService } from '../logging/logger.service'; +import { flattenArray } from '../utils/collections/collections.helper'; import { ClosestMatchingRouteService } from './closest-matching-route.service'; @Injectable() @@ -64,7 +65,7 @@ function interceptRequest( const allRoutesConfigured = allConfigurations.map( (x) => x.secureRoutes || [] ); - const allRoutesConfiguredFlat = [].concat(...allRoutesConfigured) as string[]; + const allRoutesConfiguredFlat = flattenArray(allRoutesConfigured); if (allRoutesConfiguredFlat.length === 0) { deps.loggerService.logDebug( diff --git a/projects/angular-auth-oidc-client/src/lib/interceptor/closest-matching-route.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/interceptor/closest-matching-route.service.spec.ts index ccc62290a..7cf558161 100644 --- a/projects/angular-auth-oidc-client/src/lib/interceptor/closest-matching-route.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/interceptor/closest-matching-route.service.spec.ts @@ -1,5 +1,5 @@ import { TestBed } from '@angular/core/testing'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { LoggerService } from '../logging/logger.service'; import { ClosestMatchingRouteService } from './closest-matching-route.service'; @@ -8,13 +8,7 @@ describe('ClosestMatchingRouteService', () => { beforeEach(() => { TestBed.configureTestingModule({ - providers: [ - ClosestMatchingRouteService, - { - provide: LoggerService, - useClass: mockClass(LoggerService), - }, - ], + providers: [ClosestMatchingRouteService, mockProvider(LoggerService)], }); }); diff --git a/projects/angular-auth-oidc-client/src/lib/interceptor/closest-matching-route.service.ts b/projects/angular-auth-oidc-client/src/lib/interceptor/closest-matching-route.service.ts index 2b764b49f..85a614a8e 100644 --- a/projects/angular-auth-oidc-client/src/lib/interceptor/closest-matching-route.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/interceptor/closest-matching-route.service.ts @@ -10,7 +10,7 @@ export class ClosestMatchingRouteService { for (const config of configurations) { const { secureRoutes } = config; - for (const configuredRoute of secureRoutes) { + for (const configuredRoute of secureRoutes ?? []) { if (route.startsWith(configuredRoute)) { return { matchingRoute: configuredRoute, @@ -28,6 +28,6 @@ export class ClosestMatchingRouteService { } export interface ClosestMatchingRouteResult { - matchingRoute: string; - matchingConfig: OpenIdConfiguration; + matchingRoute: string | null; + matchingConfig: OpenIdConfiguration | null; } diff --git a/projects/angular-auth-oidc-client/src/lib/logging/logger.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/logging/logger.service.spec.ts index 17acdb2b7..7da12b924 100644 --- a/projects/angular-auth-oidc-client/src/lib/logging/logger.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/logging/logger.service.spec.ts @@ -1,8 +1,8 @@ import { TestBed } from '@angular/core/testing'; -import { LoggerService } from './logger.service'; import { AbstractLoggerService } from './abstract-logger.service'; import { ConsoleLoggerService } from './console-logger.service'; import { LogLevel } from './log-level'; +import { LoggerService } from './logger.service'; describe('Logger Service', () => { let loggerService: LoggerService; @@ -73,7 +73,7 @@ describe('Logger Service', () => { const spy = spyOn(console, 'warn'); loggerService.logWarning( - { configId: 'configId1', logLevel: null }, + { configId: 'configId1', logLevel: undefined }, 'some message' ); expect(spy).not.toHaveBeenCalled(); @@ -82,7 +82,7 @@ describe('Logger Service', () => { it('should not log if no config is given', () => { const spy = spyOn(console, 'warn'); - loggerService.logWarning(null, 'some message'); + loggerService.logWarning({}, 'some message'); expect(spy).not.toHaveBeenCalled(); }); @@ -168,7 +168,7 @@ describe('Logger Service', () => { const spy = spyOn(console, 'debug'); loggerService.logDebug( - { configId: 'configId1', logLevel: null }, + { configId: 'configId1', logLevel: undefined }, 'some message' ); expect(spy).not.toHaveBeenCalled(); diff --git a/projects/angular-auth-oidc-client/src/lib/logging/logger.service.ts b/projects/angular-auth-oidc-client/src/lib/logging/logger.service.ts index cde580407..0428b2868 100644 --- a/projects/angular-auth-oidc-client/src/lib/logging/logger.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/logging/logger.service.ts @@ -70,10 +70,14 @@ export class LoggerService { } logDebug( - configuration: OpenIdConfiguration, + configuration: OpenIdConfiguration | null, message: any, ...args: any[] ): void { + if (!configuration) { + return; + } + if (!this.logLevelIsSet(configuration)) { return; } @@ -111,6 +115,10 @@ export class LoggerService { ): boolean { const { logLevel } = configuration || {}; + if (!logLevel) { + return false; + } + return logLevel <= logLevelToCompare; } diff --git a/projects/angular-auth-oidc-client/src/lib/login/login.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/login/login.service.spec.ts index 32ea683ba..bf538bda1 100644 --- a/projects/angular-auth-oidc-client/src/lib/login/login.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/login/login.service.spec.ts @@ -1,7 +1,7 @@ import { CommonModule } from '@angular/common'; import { TestBed, waitForAsync } from '@angular/core/testing'; import { of } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { StoragePersistenceService } from '../storage/storage-persistence.service'; import { LoginResponse } from './login-response'; import { LoginService } from './login.service'; @@ -23,17 +23,11 @@ describe('LoginService', () => { imports: [CommonModule], providers: [ LoginService, - { provide: ParLoginService, useClass: mockClass(ParLoginService) }, - { provide: PopUpLoginService, useClass: mockClass(PopUpLoginService) }, - { - provide: StandardLoginService, - useClass: mockClass(StandardLoginService), - }, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, - { provide: PopUpService, useClass: mockClass(PopUpService) }, + mockProvider(ParLoginService), + mockProvider(PopUpLoginService), + mockProvider(StandardLoginService), + mockProvider(StoragePersistenceService), + mockProvider(PopUpService), ], }); }); @@ -75,6 +69,7 @@ describe('LoginService', () => { }); it('stores the customParams to the storage if customParams are given', () => { + // arrange const config = { usePushedAuthorisationRequests: false }; const storagePersistenceServiceSpy = spyOn( storagePersistenceService, @@ -90,6 +85,24 @@ describe('LoginService', () => { config ); }); + + it("should throw error if configuration is null and doesn't call loginPar or loginStandard", () => { + // arrange + const config = null; + const loginParSpy = spyOn(parLoginService, 'loginPar'); + const standardLoginSpy = spyOn(standardLoginService, 'loginStandard'); + const authOptions = { customParams: { custom: 'params' } }; + + // act + const fn = (): void => service.login(config, authOptions); + + // assert + expect(fn).toThrow( + new Error('Please provide a configuration before setting up the module') + ); + expect(loginParSpy).not.toHaveBeenCalled(); + expect(standardLoginSpy).not.toHaveBeenCalled(); + }); }); describe('loginWithPopUp', () => { @@ -99,11 +112,11 @@ describe('LoginService', () => { const loginWithPopUpPar = spyOn( parLoginService, 'loginWithPopUpPar' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as LoginResponse)); const loginWithPopUpStandardSpy = spyOn( popUpLoginService, 'loginWithPopUpStandard' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as LoginResponse)); // act service.loginWithPopUp(config, [config]).subscribe(() => { @@ -119,11 +132,11 @@ describe('LoginService', () => { const loginWithPopUpPar = spyOn( parLoginService, 'loginWithPopUpPar' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as LoginResponse)); const loginWithPopUpStandardSpy = spyOn( popUpLoginService, 'loginWithPopUpStandard' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as LoginResponse)); // act service.loginWithPopUp(config, [config]).subscribe(() => { @@ -143,7 +156,7 @@ describe('LoginService', () => { const authOptions = { customParams: { custom: 'params' } }; spyOn(popUpLoginService, 'loginWithPopUpStandard').and.returnValue( - of(null) + of({} as LoginResponse) ); // act @@ -164,11 +177,11 @@ describe('LoginService', () => { const loginWithPopUpPar = spyOn( parLoginService, 'loginWithPopUpPar' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as LoginResponse)); const loginWithPopUpStandardSpy = spyOn( popUpLoginService, 'loginWithPopUpStandard' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as LoginResponse)); spyOn(popUpService, 'isCurrentlyInPopup').and.returnValue(true); diff --git a/projects/angular-auth-oidc-client/src/lib/login/login.service.ts b/projects/angular-auth-oidc-client/src/lib/login/login.service.ts index 601148b3f..ca712a2d6 100644 --- a/projects/angular-auth-oidc-client/src/lib/login/login.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/login/login.service.ts @@ -20,7 +20,16 @@ export class LoginService { private readonly popupService: PopUpService ) {} - login(configuration: OpenIdConfiguration, authOptions?: AuthOptions): void { + login( + configuration: OpenIdConfiguration | null, + authOptions?: AuthOptions + ): void { + if (!configuration) { + throw new Error( + 'Please provide a configuration before setting up the module' + ); + } + const { usePushedAuthorisationRequests } = configuration; if (authOptions?.customParams) { @@ -42,11 +51,17 @@ export class LoginService { } loginWithPopUp( - configuration: OpenIdConfiguration, + configuration: OpenIdConfiguration | null, allConfigs: OpenIdConfiguration[], authOptions?: AuthOptions, popupOptions?: PopupOptions ): Observable { + if (!configuration) { + throw new Error( + 'Please provide a configuration before setting up the module' + ); + } + const isAlreadyInPopUp = this.popupService.isCurrentlyInPopup(configuration); diff --git a/projects/angular-auth-oidc-client/src/lib/login/par/par-login.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/login/par/par-login.service.spec.ts index 3f03950ce..02e0a99df 100644 --- a/projects/angular-auth-oidc-client/src/lib/login/par/par-login.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/login/par/par-login.service.spec.ts @@ -1,11 +1,12 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { of } from 'rxjs'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { CheckAuthService } from '../../auth-state/check-auth.service'; import { AuthWellKnownService } from '../../config/auth-well-known/auth-well-known.service'; import { LoggerService } from '../../logging/logger.service'; import { RedirectService } from '../../utils/redirect/redirect.service'; import { UrlService } from '../../utils/url/url.service'; +import { LoginResponse } from '../login-response'; import { PopupResult } from '../popup/popup-result'; import { PopUpService } from '../popup/popup.service'; import { ResponseTypeValidationService } from '../response-type-validation/response-type-validation.service'; @@ -28,38 +29,14 @@ describe('ParLoginService', () => { TestBed.configureTestingModule({ providers: [ ParLoginService, - { - provide: LoggerService, - useClass: mockClass(LoggerService), - }, - { - provide: ResponseTypeValidationService, - useClass: mockClass(ResponseTypeValidationService), - }, - { - provide: UrlService, - useClass: mockClass(UrlService), - }, - { - provide: RedirectService, - useClass: mockClass(RedirectService), - }, - { - provide: AuthWellKnownService, - useClass: mockClass(AuthWellKnownService), - }, - { - provide: PopUpService, - useClass: mockClass(PopUpService), - }, - { - provide: CheckAuthService, - useClass: mockClass(CheckAuthService), - }, - { - provide: ParService, - useClass: mockClass(ParService), - }, + mockProvider(LoggerService), + mockProvider(ResponseTypeValidationService), + mockProvider(UrlService), + mockProvider(RedirectService), + mockProvider(AuthWellKnownService), + mockProvider(PopUpService), + mockProvider(CheckAuthService), + mockProvider(ParService), ], }); }); @@ -225,7 +202,7 @@ describe('ParLoginService', () => { spyOn(urlService, 'getAuthorizeParUrl').and.returnValue('some-par-url'); const redirectToSpy = spyOn(redirectService, 'redirectTo'); const spy = jasmine.createSpy(); - const urlHandler = (url): void => { + const urlHandler = (url: any): void => { spy(url); }; @@ -376,7 +353,9 @@ describe('ParLoginService', () => { of({ requestUri: 'requestUri' } as ParResponse) ); spyOn(urlService, 'getAuthorizeParUrl').and.returnValue('some-par-url'); - spyOn(checkAuthService, 'checkAuth').and.returnValue(of(null)); + spyOn(checkAuthService, 'checkAuth').and.returnValue( + of({} as LoginResponse) + ); spyOnProperty(popupService, 'result$').and.returnValue( of({} as PopupResult) ); @@ -413,7 +392,7 @@ describe('ParLoginService', () => { of({ isAuthenticated: true, configId: 'configId1', - idToken: null, + idToken: '', userData: { any: 'userData' }, accessToken: 'anyAccessToken', }) @@ -435,7 +414,7 @@ describe('ParLoginService', () => { expect(result).toEqual({ isAuthenticated: true, configId: 'configId1', - idToken: null, + idToken: '', userData: { any: 'userData' }, accessToken: 'anyAccessToken', }); @@ -465,7 +444,7 @@ describe('ParLoginService', () => { spyOn(urlService, 'getAuthorizeParUrl').and.returnValue('some-par-url'); const checkAuthSpy = spyOn(checkAuthService, 'checkAuth'); - const popupResult: PopupResult = { userClosed: true }; + const popupResult = { userClosed: true } as PopupResult; spyOnProperty(popupService, 'result$').and.returnValue(of(popupResult)); @@ -475,9 +454,9 @@ describe('ParLoginService', () => { isAuthenticated: false, errorMessage: 'User closed popup', configId: 'configId1', - idToken: null, + idToken: '', userData: null, - accessToken: null, + accessToken: '', }); }); })); diff --git a/projects/angular-auth-oidc-client/src/lib/login/par/par-login.service.ts b/projects/angular-auth-oidc-client/src/lib/login/par/par-login.service.ts index f5708133d..ac708d238 100644 --- a/projects/angular-auth-oidc-client/src/lib/login/par/par-login.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/login/par/par-login.service.ts @@ -10,7 +10,7 @@ import { RedirectService } from '../../utils/redirect/redirect.service'; import { UrlService } from '../../utils/url/url.service'; import { LoginResponse } from '../login-response'; import { PopupOptions } from '../popup/popup-options'; -import { PopupResultReceivedUrl } from '../popup/popup-result'; +import { PopupResult } from '../popup/popup-result'; import { PopUpService } from '../popup/popup.service'; import { ResponseTypeValidationService } from '../response-type-validation/response-type-validation.service'; import { ParResponse } from './par-response'; @@ -74,7 +74,7 @@ export class ParLoginService { return; } - if (authOptions.urlHandler) { + if (authOptions?.urlHandler) { authOptions.urlHandler(url); } else { this.redirectService.redirectTo(url); @@ -116,8 +116,7 @@ export class ParLoginService { switchMap((response: ParResponse) => { this.loggerService.logDebug( configuration, - 'par response: ', - response + `par response: ${response}` ); const url = this.urlService.getAuthorizeParUrl( @@ -139,7 +138,7 @@ export class ParLoginService { return this.popupService.result$.pipe( take(1), - switchMap((result: PopupResultReceivedUrl) => { + switchMap((result: PopupResult) => { const { userClosed, receivedUrl } = result; if (userClosed) { @@ -147,8 +146,8 @@ export class ParLoginService { isAuthenticated: false, errorMessage: 'User closed popup', userData: null, - idToken: null, - accessToken: null, + idToken: '', + accessToken: '', configId, }); } diff --git a/projects/angular-auth-oidc-client/src/lib/login/par/par.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/login/par/par.service.spec.ts index 40f56e119..7a222d7f7 100644 --- a/projects/angular-auth-oidc-client/src/lib/login/par/par.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/login/par/par.service.spec.ts @@ -1,7 +1,7 @@ import { HttpHeaders } from '@angular/common/http'; import { TestBed, waitForAsync } from '@angular/core/testing'; import { of, throwError } from 'rxjs'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { createRetriableStream } from '../../../test/create-retriable-stream.helper'; import { DataService } from '../../api/data.service'; import { LoggerService } from '../../logging/logger.service'; @@ -19,23 +19,10 @@ describe('ParService', () => { beforeEach(() => { TestBed.configureTestingModule({ providers: [ - ParService, - { - provide: LoggerService, - useClass: mockClass(LoggerService), - }, - { - provide: UrlService, - useClass: mockClass(UrlService), - }, - { - provide: DataService, - useClass: mockClass(DataService), - }, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, + mockProvider(LoggerService), + mockProvider(UrlService), + mockProvider(DataService), + mockProvider(StoragePersistenceService), ], }); }); @@ -55,7 +42,7 @@ describe('ParService', () => { describe('postParRequest', () => { it('throws error if authWellKnownEndPoints does not exist in storage', waitForAsync(() => { spyOn(urlService, 'createBodyForParCodeFlowRequest').and.returnValue( - null + of(null) ); spyOn(storagePersistenceService, 'read') .withArgs('authWellKnownEndPoints', { configId: 'configId1' }) @@ -71,7 +58,7 @@ describe('ParService', () => { it('throws error if par endpoint does not exist in storage', waitForAsync(() => { spyOn(urlService, 'createBodyForParCodeFlowRequest').and.returnValue( - null + of(null) ); spyOn(storagePersistenceService, 'read') .withArgs('authWellKnownEndPoints', { configId: 'configId1' }) diff --git a/projects/angular-auth-oidc-client/src/lib/login/popup/popup-login.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/login/popup/popup-login.service.spec.ts index 2a19d4065..9d8116e39 100644 --- a/projects/angular-auth-oidc-client/src/lib/login/popup/popup-login.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/login/popup/popup-login.service.spec.ts @@ -1,11 +1,12 @@ import { CommonModule } from '@angular/common'; import { TestBed, waitForAsync } from '@angular/core/testing'; import { of } from 'rxjs'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { CheckAuthService } from '../../auth-state/check-auth.service'; import { AuthWellKnownService } from '../../config/auth-well-known/auth-well-known.service'; import { LoggerService } from '../../logging/logger.service'; import { UrlService } from '../../utils/url/url.service'; +import { LoginResponse } from '../login-response'; import { ResponseTypeValidationService } from '../response-type-validation/response-type-validation.service'; import { PopUpLoginService } from './popup-login.service'; import { PopupResult } from './popup-result'; @@ -25,18 +26,12 @@ describe('PopUpLoginService', () => { imports: [CommonModule], providers: [ PopUpLoginService, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { - provide: ResponseTypeValidationService, - useClass: mockClass(ResponseTypeValidationService), - }, - { provide: UrlService, useClass: mockClass(UrlService) }, - { - provide: AuthWellKnownService, - useClass: mockClass(AuthWellKnownService), - }, - { provide: PopUpService, useClass: mockClass(PopUpService) }, - { provide: CheckAuthService, useClass: mockClass(CheckAuthService) }, + mockProvider(LoggerService), + mockProvider(ResponseTypeValidationService), + mockProvider(UrlService), + mockProvider(AuthWellKnownService), + mockProvider(PopUpService), + mockProvider(CheckAuthService), ], }); }); @@ -93,7 +88,9 @@ describe('PopUpLoginService', () => { of({} as PopupResult) ); spyOn(urlService, 'getAuthorizeUrl').and.returnValue(of('someUrl')); - spyOn(checkAuthService, 'checkAuth').and.returnValue(of(null)); + spyOn(checkAuthService, 'checkAuth').and.returnValue( + of({} as LoginResponse) + ); popUpLoginService .loginWithPopUpStandard(config, [config]) @@ -120,7 +117,9 @@ describe('PopUpLoginService', () => { spyOnProperty(popupService, 'result$').and.returnValue( of({} as PopupResult) ); - spyOn(checkAuthService, 'checkAuth').and.returnValue(of(null)); + spyOn(checkAuthService, 'checkAuth').and.returnValue( + of({} as LoginResponse) + ); const popupSpy = spyOn(popupService, 'openPopUp'); popUpLoginService @@ -150,7 +149,7 @@ describe('PopUpLoginService', () => { of({ isAuthenticated: true, configId: 'configId1', - idToken: null, + idToken: '', userData: { any: 'userData' }, accessToken: 'anyAccessToken', }) @@ -174,7 +173,7 @@ describe('PopUpLoginService', () => { expect(result).toEqual({ isAuthenticated: true, configId: 'configId1', - idToken: null, + idToken: '', userData: { any: 'userData' }, accessToken: 'anyAccessToken', }); @@ -199,9 +198,9 @@ describe('PopUpLoginService', () => { spyOn(urlService, 'getAuthorizeUrl').and.returnValue(of('someUrl')); spyOn(popupService, 'openPopUp'); const checkAuthSpy = spyOn(checkAuthService, 'checkAuth').and.returnValue( - of(null) + of({} as LoginResponse) ); - const popupResult: PopupResult = { userClosed: true }; + const popupResult = { userClosed: true } as PopupResult; spyOnProperty(popupService, 'result$').and.returnValue(of(popupResult)); @@ -213,9 +212,9 @@ describe('PopUpLoginService', () => { isAuthenticated: false, errorMessage: 'User closed popup', configId: 'configId1', - idToken: null, + idToken: '', userData: null, - accessToken: null, + accessToken: '', }); }); })); diff --git a/projects/angular-auth-oidc-client/src/lib/login/popup/popup-login.service.ts b/projects/angular-auth-oidc-client/src/lib/login/popup/popup-login.service.ts index c6e570062..b61e07424 100644 --- a/projects/angular-auth-oidc-client/src/lib/login/popup/popup-login.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/login/popup/popup-login.service.ts @@ -8,10 +8,10 @@ import { OpenIdConfiguration } from '../../config/openid-configuration'; import { LoggerService } from '../../logging/logger.service'; import { UrlService } from '../../utils/url/url.service'; import { LoginResponse } from '../login-response'; +import { ResponseTypeValidationService } from '../response-type-validation/response-type-validation.service'; import { PopupOptions } from './popup-options'; +import { PopupResult } from './popup-result'; import { PopUpService } from './popup.service'; -import { ResponseTypeValidationService } from '../response-type-validation/response-type-validation.service'; -import { PopupResultReceivedUrl } from './popup-result'; @Injectable({ providedIn: 'root' }) export class PopUpLoginService { @@ -55,24 +55,26 @@ export class PopUpLoginService { switchMap(() => this.urlService.getAuthorizeUrl(configuration, authOptions) ), - tap((authUrl: string) => + tap((authUrl) => this.popupService.openPopUp(authUrl, popupOptions, configuration) ), switchMap(() => { return this.popupService.result$.pipe( take(1), - switchMap((result: PopupResultReceivedUrl) => { + switchMap((result: PopupResult) => { const { userClosed, receivedUrl } = result; if (userClosed) { - return of({ + const response: LoginResponse = { isAuthenticated: false, errorMessage: 'User closed popup', userData: null, - idToken: null, - accessToken: null, + idToken: '', + accessToken: '', configId, - }); + }; + + return of(response); } return this.checkAuthService.checkAuth( diff --git a/projects/angular-auth-oidc-client/src/lib/login/popup/popup-result.ts b/projects/angular-auth-oidc-client/src/lib/login/popup/popup-result.ts index 00ee4f082..dbd44793f 100644 --- a/projects/angular-auth-oidc-client/src/lib/login/popup/popup-result.ts +++ b/projects/angular-auth-oidc-client/src/lib/login/popup/popup-result.ts @@ -1,10 +1,4 @@ -export interface PopupResultUserClosed { - userClosed: true; -} - -export interface PopupResultReceivedUrl { - userClosed: false; +export interface PopupResult { + userClosed: boolean; receivedUrl: string; } - -export type PopupResult = PopupResultUserClosed | PopupResultReceivedUrl; diff --git a/projects/angular-auth-oidc-client/src/lib/login/popup/popup.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/login/popup/popup.service.spec.ts index 6169df9bb..27d714e13 100644 --- a/projects/angular-auth-oidc-client/src/lib/login/popup/popup.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/login/popup/popup.service.spec.ts @@ -1,5 +1,5 @@ import { fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { OpenIdConfiguration } from '../../config/openid-configuration'; import { LoggerService } from '../../logging/logger.service'; import { StoragePersistenceService } from '../../storage/storage-persistence.service'; @@ -14,12 +14,8 @@ describe('PopUpService', () => { beforeEach(() => { TestBed.configureTestingModule({ providers: [ - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - PopUpService, + mockProvider(StoragePersistenceService), + mockProvider(LoggerService), ], }); }); @@ -30,7 +26,7 @@ describe('PopUpService', () => { popUpService = TestBed.inject(PopUpService); }); - let store = {}; + let store: any = {}; const mockStorage = { getItem: (key: string): string => { return key in store ? store[key] : null; @@ -45,7 +41,7 @@ describe('PopUpService', () => { store = {}; }, length: 1, - key: (_i): string => '', + key: (_i: any): string => '', }; it('should create', () => { @@ -199,21 +195,23 @@ describe('PopUpService', () => { cleanUpSpy = spyOn(popUpService as any, 'cleanUp').and.callThrough(); - popupResult = undefined; + popupResult = {} as PopupResult; popUpService.result$.subscribe((result) => (popupResult = result)); }); it('message received with data', fakeAsync(() => { - let listener: (event: MessageEvent) => void; + let listener: (event: MessageEvent) => void = () => { + return; + }; spyOn(window, 'addEventListener').and.callFake( - (_, func) => (listener = func) + (_: any, func: any) => (listener = func) ); popUpService.openPopUp('url', {}, { configId: 'configId1' }); - expect(popupResult).toBeUndefined(); + expect(popupResult).toEqual({} as PopupResult); expect(cleanUpSpy).not.toHaveBeenCalled(); listener(new MessageEvent('message', { data: 'some-url1111' })); @@ -230,38 +228,43 @@ describe('PopUpService', () => { })); it('message received without data does return but cleanup does not throw event', fakeAsync(() => { - let listener: (event: MessageEvent) => void; + let listener: (event: MessageEvent) => void = () => { + return; + }; spyOn(window, 'addEventListener').and.callFake( - (_, func) => (listener = func) + (_: any, func: any) => (listener = func) ); const nextSpy = spyOn((popUpService as any).resultInternal$, 'next'); popUpService.openPopUp('url', {}, { configId: 'configId1' }); - expect(popupResult).toBeUndefined(); + expect(popupResult).toEqual({} as PopupResult); expect(cleanUpSpy).not.toHaveBeenCalled(); listener(new MessageEvent('message', { data: null })); tick(200); - expect(popupResult).toBeUndefined(); + expect(popupResult).toEqual({} as PopupResult); expect(cleanUpSpy).toHaveBeenCalled(); expect(nextSpy).not.toHaveBeenCalled(); })); it('user closed', fakeAsync(() => { - popUpService.openPopUp('url', {}, { configId: 'configId1' }); + popUpService.openPopUp('url', undefined, { configId: 'configId1' }); - expect(popupResult).toBeUndefined(); + expect(popupResult).toEqual({} as PopupResult); expect(cleanUpSpy).not.toHaveBeenCalled(); (popup as any).closed = true; tick(200); - expect(popupResult).toEqual({ userClosed: true }); + expect(popupResult).toEqual({ + userClosed: true, + receivedUrl: '', + } as PopupResult); expect(cleanUpSpy).toHaveBeenCalled(); })); }); @@ -275,7 +278,7 @@ describe('PopUpService', () => { const sendMessageSpy = spyOn(popUpService as any, 'sendMessage'); // act - popUpService.sendMessageToMainWindow(''); + popUpService.sendMessageToMainWindow('', {}); // assert expect(sendMessageSpy).not.toHaveBeenCalled(); @@ -289,7 +292,7 @@ describe('PopUpService', () => { const sendMessageSpy = spyOn(window.opener, 'postMessage'); // act - popUpService.sendMessageToMainWindow('someUrl'); + popUpService.sendMessageToMainWindow('someUrl', {}); // assert expect(sendMessageSpy).toHaveBeenCalledOnceWith( @@ -305,7 +308,7 @@ describe('PopUpService', () => { const spy = spyOn(window, 'removeEventListener').and.callFake( () => undefined ); - const listener = null; + const listener: any = null; // act (popUpService as any).cleanUp(listener, { configId: 'configId1' }); diff --git a/projects/angular-auth-oidc-client/src/lib/login/popup/popup.service.ts b/projects/angular-auth-oidc-client/src/lib/login/popup/popup.service.ts index 0a53b6334..cc05a0497 100644 --- a/projects/angular-auth-oidc-client/src/lib/login/popup/popup.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/login/popup/popup.service.ts @@ -11,9 +11,9 @@ import { PopupResult } from './popup-result'; export class PopUpService { private readonly STORAGE_IDENTIFIER = 'popupauth'; - private popUp: Window; + private popUp: Window | null = null; - private handle: number; + private handle = -1; private readonly resultInternal$ = new Subject(); @@ -21,7 +21,7 @@ export class PopUpService { return this.resultInternal$.asObservable(); } - private get windowInternal(): Window { + private get windowInternal(): Window | null { return this.document.defaultView; } @@ -38,10 +38,16 @@ export class PopUpService { config ); + const windowIdentifier = this.windowInternal; + + if (!windowIdentifier) { + return false; + } + return ( - !!this.windowInternal.opener && - this.windowInternal.opener !== this.windowInternal && - !!popup + Boolean(windowIdentifier.opener) && + windowIdentifier.opener !== windowIdentifier && + Boolean(popup) ); } @@ -49,8 +55,8 @@ export class PopUpService { } openPopUp( - url: string, - popupOptions: PopupOptions, + url: string | null, + popupOptions: PopupOptions | undefined, config: OpenIdConfiguration ): void { const optionsToPass = this.getOptions(popupOptions); @@ -61,7 +67,19 @@ export class PopUpService { config ); - this.popUp = this.windowInternal.open(url, '_blank', optionsToPass); + const windowIdentifier = this.windowInternal; + + if (!windowIdentifier) { + return; + } + + if (!url) { + this.loggerService.logError(config, 'Could not open popup, url is empty'); + + return; + } + + this.popUp = windowIdentifier.open(url, '_blank', optionsToPass); if (!this.popUp) { this.storagePersistenceService.remove(this.STORAGE_IDENTIFIER, config); @@ -89,28 +107,40 @@ export class PopUpService { this.cleanUp(listener, config); }; - this.windowInternal.addEventListener('message', listener, false); + windowIdentifier.addEventListener('message', listener, false); - this.handle = this.windowInternal.setInterval(() => { + this.handle = windowIdentifier.setInterval(() => { if (this.popUp?.closed) { - this.resultInternal$.next({ userClosed: true }); + this.resultInternal$.next({ userClosed: true, receivedUrl: '' }); this.cleanUp(listener, config); } }, 200); } - sendMessageToMainWindow(url: string): void { - if (this.windowInternal.opener) { - const href = this.windowInternal.location.href; + sendMessageToMainWindow(url: string, config: OpenIdConfiguration): void { + const windowIdentifier = this.windowInternal; - this.sendMessage(url, href); + if (!windowIdentifier) { + return; + } + + if (windowIdentifier.opener) { + const href = windowIdentifier.location.href; + + this.sendMessage(url, href, config); } } private cleanUp(listener: any, config: OpenIdConfiguration): void { - this.windowInternal.removeEventListener('message', listener, false); - this.windowInternal.clearInterval(this.handle); + const windowIdentifier = this.windowInternal; + + if (!windowIdentifier) { + return; + } + + windowIdentifier.removeEventListener('message', listener, false); + windowIdentifier.clearInterval(this.handle); if (this.popUp) { this.storagePersistenceService.remove(this.STORAGE_IDENTIFIER, config); @@ -119,12 +149,31 @@ export class PopUpService { } } - private sendMessage(url: string, href: string): void { - this.windowInternal.opener.postMessage(url, href); + private sendMessage( + url: string, + href: string, + config: OpenIdConfiguration + ): void { + const windowIdentifier = this.windowInternal; + + if (!windowIdentifier) { + return; + } + + if (!url) { + this.loggerService.logDebug( + config, + `Can not send message to parent, no url: '${url}'` + ); + + return; + } + + windowIdentifier.opener.postMessage(url, href); } - private getOptions(popupOptions: PopupOptions): string { - const popupDefaultOptions: PopupOptions = { + private getOptions(popupOptions: PopupOptions | undefined): string { + const popupDefaultOptions = { width: 500, height: 500, left: 50, @@ -134,12 +183,19 @@ export class PopUpService { ...popupDefaultOptions, ...(popupOptions || {}), }; + const windowIdentifier = this.windowInternal; + + if (!windowIdentifier) { + return ''; + } + + const width = options.width || popupDefaultOptions.width; + const height = options.height || popupDefaultOptions.height; + const left: number = - this.windowInternal.screenLeft + - (this.windowInternal.outerWidth - options.width) / 2; + windowIdentifier.screenLeft + (windowIdentifier.outerWidth - width) / 2; const top: number = - this.windowInternal.screenTop + - (this.windowInternal.outerHeight - options.height) / 2; + windowIdentifier.screenTop + (windowIdentifier.outerHeight - height) / 2; options.left = left; options.top = top; diff --git a/projects/angular-auth-oidc-client/src/lib/login/response-type-validation/response-type-validation.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/login/response-type-validation/response-type-validation.service.spec.ts index a9ed28cc8..679841c19 100644 --- a/projects/angular-auth-oidc-client/src/lib/login/response-type-validation/response-type-validation.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/login/response-type-validation/response-type-validation.service.spec.ts @@ -1,5 +1,5 @@ import { TestBed } from '@angular/core/testing'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { LoggerService } from '../../logging/logger.service'; import { FlowHelper } from '../../utils/flowHelper/flow-helper.service'; import { ResponseTypeValidationService } from './response-type-validation.service'; @@ -13,14 +13,8 @@ describe('ResponseTypeValidationService', () => { imports: [], providers: [ ResponseTypeValidationService, - { - provide: LoggerService, - useClass: mockClass(LoggerService), - }, - { - provide: FlowHelper, - useClass: mockClass(FlowHelper), - }, + mockProvider(LoggerService), + mockProvider(FlowHelper), ], }); }); diff --git a/projects/angular-auth-oidc-client/src/lib/login/standard/standard-login.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/login/standard/standard-login.service.spec.ts index 8ae593aa4..4313ccc20 100644 --- a/projects/angular-auth-oidc-client/src/lib/login/standard/standard-login.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/login/standard/standard-login.service.spec.ts @@ -1,6 +1,6 @@ import { fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing'; import { of } from 'rxjs'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { AuthWellKnownService } from '../../config/auth-well-known/auth-well-known.service'; import { FlowsDataService } from '../../flows/flows-data.service'; import { LoggerService } from '../../logging/logger.service'; @@ -23,18 +23,12 @@ describe('StandardLoginService', () => { imports: [], providers: [ StandardLoginService, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { - provide: ResponseTypeValidationService, - useClass: mockClass(ResponseTypeValidationService), - }, - { provide: UrlService, useClass: mockClass(UrlService) }, - { provide: RedirectService, useClass: mockClass(RedirectService) }, - { - provide: AuthWellKnownService, - useClass: mockClass(AuthWellKnownService), - }, - { provide: FlowsDataService, useClass: mockClass(FlowsDataService) }, + mockProvider(LoggerService), + mockProvider(ResponseTypeValidationService), + mockProvider(UrlService), + mockProvider(RedirectService), + mockProvider(AuthWellKnownService), + mockProvider(FlowsDataService), ], }); }); @@ -160,7 +154,7 @@ describe('StandardLoginService', () => { () => undefined ); const spy = jasmine.createSpy(); - const urlHandler = (url): void => { + const urlHandler = (url: any): void => { spy(url); }; diff --git a/projects/angular-auth-oidc-client/src/lib/login/standard/standard-login.service.ts b/projects/angular-auth-oidc-client/src/lib/login/standard/standard-login.service.ts index c38e921da..290aa5d30 100644 --- a/projects/angular-auth-oidc-client/src/lib/login/standard/standard-login.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/login/standard/standard-login.service.ts @@ -1,12 +1,12 @@ import { Injectable } from '@angular/core'; import { AuthOptions } from '../../auth-options'; import { AuthWellKnownService } from '../../config/auth-well-known/auth-well-known.service'; +import { OpenIdConfiguration } from '../../config/openid-configuration'; import { FlowsDataService } from '../../flows/flows-data.service'; import { LoggerService } from '../../logging/logger.service'; import { RedirectService } from '../../utils/redirect/redirect.service'; import { UrlService } from '../../utils/url/url.service'; import { ResponseTypeValidationService } from '../response-type-validation/response-type-validation.service'; -import { OpenIdConfiguration } from '../../config/openid-configuration'; @Injectable({ providedIn: 'root' }) export class StandardLoginService { @@ -48,7 +48,7 @@ export class StandardLoginService { this.urlService .getAuthorizeUrl(configuration, authOptions) - .subscribe((url: string) => { + .subscribe((url) => { if (!url) { this.loggerService.logError( configuration, diff --git a/projects/angular-auth-oidc-client/src/lib/logoff-revoke/logoff-revocation.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/logoff-revoke/logoff-revocation.service.spec.ts index 9315be72f..94d62992a 100644 --- a/projects/angular-auth-oidc-client/src/lib/logoff-revoke/logoff-revocation.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/logoff-revoke/logoff-revocation.service.spec.ts @@ -1,7 +1,7 @@ import { HttpHeaders } from '@angular/common/http'; import { TestBed, waitForAsync } from '@angular/core/testing'; import { Observable, of, throwError } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { createRetriableStream } from '../../test/create-retriable-stream.helper'; import { DataService } from '../api/data.service'; import { ResetAuthDataService } from '../flows/reset-auth-data.service'; @@ -25,23 +25,13 @@ describe('Logout and Revoke Service', () => { beforeEach(() => { TestBed.configureTestingModule({ providers: [ - LogoffRevocationService, - { provide: DataService, useClass: mockClass(DataService) }, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, - { provide: UrlService, useClass: mockClass(UrlService) }, - { - provide: CheckSessionService, - useClass: mockClass(CheckSessionService), - }, - { - provide: ResetAuthDataService, - useClass: mockClass(ResetAuthDataService), - }, - { provide: RedirectService, useClass: mockClass(RedirectService) }, + mockProvider(DataService), + mockProvider(LoggerService), + mockProvider(StoragePersistenceService), + mockProvider(UrlService), + mockProvider(CheckSessionService), + mockProvider(ResetAuthDataService), + mockProvider(RedirectService), ], }); }); @@ -477,7 +467,7 @@ describe('Logout and Revoke Service', () => { // Arrange spyOn(urlService, 'getEndSessionUrl').and.returnValue('someValue'); const spy = jasmine.createSpy(); - const urlHandler = (url): void => { + const urlHandler = (url: string): void => { spy(url); }; const redirectSpy = spyOn(redirectService, 'redirectTo'); @@ -749,7 +739,7 @@ describe('Logout and Revoke Service', () => { ); spyOn(service, 'revokeAccessToken').and.returnValue(of({ any: 'thing' })); const logoffSpy = spyOn(service, 'logoff').and.returnValue(of(null)); - const urlHandler = (_url): void => undefined; + const urlHandler = (_url: string): void => undefined; const config = { configId: 'configId1' }; // Act @@ -771,7 +761,7 @@ describe('Logout and Revoke Service', () => { .withArgs('authWellKnownEndPoints', config) .and.returnValue({ revocationEndpoint: 'revocationEndpoint' }); - spyOn(storagePersistenceService, 'getRefreshToken').and.returnValue(null); + spyOn(storagePersistenceService, 'getRefreshToken').and.returnValue(''); const revokeRefreshTokenSpy = spyOn(service, 'revokeRefreshToken'); const revokeAccessTokenSpy = spyOn( service, @@ -793,7 +783,7 @@ describe('Logout and Revoke Service', () => { spyOn(storagePersistenceService, 'read') .withArgs('authWellKnownEndPoints', config) .and.returnValue({ revocationEndpoint: 'revocationEndpoint' }); - spyOn(storagePersistenceService, 'getRefreshToken').and.returnValue(null); + spyOn(storagePersistenceService, 'getRefreshToken').and.returnValue(''); const loggerSpy = spyOn(loggerService, 'logError'); spyOn(service, 'revokeAccessToken').and.returnValue( diff --git a/projects/angular-auth-oidc-client/src/lib/logoff-revoke/logoff-revocation.service.ts b/projects/angular-auth-oidc-client/src/lib/logoff-revoke/logoff-revocation.service.ts index 8c163e1c7..ecface23f 100644 --- a/projects/angular-auth-oidc-client/src/lib/logoff-revoke/logoff-revocation.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/logoff-revoke/logoff-revocation.service.ts @@ -28,10 +28,19 @@ export class LogoffRevocationService { // Logs out on the server and the local client. // If the server state has changed, check session, then only a local logout. logoff( - config: OpenIdConfiguration, + config: OpenIdConfiguration | null, allConfigs: OpenIdConfiguration[], logoutAuthOptions?: LogoutAuthOptions ): Observable { + if (!config) { + return throwError( + () => + new Error( + 'Please provide a configuration before setting up the module' + ) + ); + } + this.loggerService.logDebug( config, 'logoff, remove auth', @@ -83,7 +92,7 @@ export class LogoffRevocationService { } logoffLocal( - config: OpenIdConfiguration, + config: OpenIdConfiguration | null, allConfigs: OpenIdConfiguration[] ): void { this.resetAuthDataService.resetAuthorizationData(config, allConfigs); @@ -99,10 +108,19 @@ export class LogoffRevocationService { // The refresh token and and the access token are revoked on the server. If the refresh token does not exist // only the access token is revoked. Then the logout run. logoffAndRevokeTokens( - config: OpenIdConfiguration, + config: OpenIdConfiguration | null, allConfigs: OpenIdConfiguration[], logoutAuthOptions?: LogoutAuthOptions ): Observable { + if (!config) { + return throwError( + () => + new Error( + 'Please provide a configuration before setting up the module' + ) + ); + } + const { revocationEndpoint } = this.storagePersistenceService.read('authWellKnownEndPoints', config) || {}; @@ -144,9 +162,18 @@ export class LogoffRevocationService { // the storage is revoked. You can pass any token to revoke. This makes it possible to // manage your own tokens. The is a public API. revokeAccessToken( - configuration: OpenIdConfiguration, + configuration: OpenIdConfiguration | null, accessToken?: any ): Observable { + if (!configuration) { + return throwError( + () => + new Error( + 'Please provide a configuration before setting up the module' + ) + ); + } + const accessTok = accessToken || this.storagePersistenceService.getAccessToken(configuration); @@ -163,9 +190,18 @@ export class LogoffRevocationService { // If no token is provided, then the token from the storage is revoked. You can pass any token to revoke. // This makes it possible to manage your own tokens. revokeRefreshToken( - configuration: OpenIdConfiguration, + configuration: OpenIdConfiguration | null, refreshToken?: any ): Observable { + if (!configuration) { + return throwError( + () => + new Error( + 'Please provide a configuration before setting up the module' + ) + ); + } + const refreshTok = refreshToken || this.storagePersistenceService.getRefreshToken(configuration); @@ -178,7 +214,7 @@ export class LogoffRevocationService { } private logoffInternal( - logoutAuthOptions: LogoutAuthOptions, + logoutAuthOptions: LogoutAuthOptions | undefined, endSessionUrl: string, config: OpenIdConfiguration, allConfigs: OpenIdConfiguration[] @@ -222,7 +258,7 @@ export class LogoffRevocationService { private sendRevokeRequest( configuration: OpenIdConfiguration, - body: string + body: string | null ): Observable { const url = this.urlService.getRevocationEndpointUrl(configuration); const headers = this.getHeaders(); diff --git a/projects/angular-auth-oidc-client/src/lib/oidc.security.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/oidc.security.service.spec.ts index 5ac85c196..9385c6dc7 100644 --- a/projects/angular-auth-oidc-client/src/lib/oidc.security.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/oidc.security.service.spec.ts @@ -1,6 +1,6 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { Observable, of } from 'rxjs'; -import { mockClass } from '../test/auto-mock'; +import { mockProvider } from '../test/auto-mock'; import { AuthenticatedResult } from './auth-state/auth-result'; import { AuthStateService } from './auth-state/auth-state.service'; import { CheckAuthService } from './auth-state/check-auth.service'; @@ -10,6 +10,7 @@ import { AuthWellKnownService } from './config/auth-well-known/auth-well-known.s import { ConfigurationService } from './config/config.service'; import { FlowsDataService } from './flows/flows-data.service'; import { CheckSessionService } from './iframe/check-session.service'; +import { LoginResponse } from './login/login-response'; import { LoginService } from './login/login.service'; import { LogoffRevocationService } from './logoff-revoke/logoff-revocation.service'; import { OidcSecurityService } from './oidc.security.service'; @@ -39,46 +40,19 @@ describe('OidcSecurityService', () => { imports: [], providers: [ OidcSecurityService, - { - provide: CheckSessionService, - useClass: mockClass(CheckSessionService), - }, - { - provide: CheckAuthService, - useClass: mockClass(CheckAuthService), - }, - { - provide: UserService, - useClass: mockClass(UserService), - }, - { - provide: TokenHelperService, - useClass: mockClass(TokenHelperService), - }, - { - provide: ConfigurationService, - useClass: mockClass(ConfigurationService), - }, - { - provide: AuthStateService, - useClass: mockClass(AuthStateService), - }, - { provide: FlowsDataService, useClass: mockClass(FlowsDataService) }, - { provide: CallbackService, useClass: mockClass(CallbackService) }, - { - provide: LogoffRevocationService, - useClass: mockClass(LogoffRevocationService), - }, - { provide: LoginService, useClass: mockClass(LoginService) }, - { - provide: RefreshSessionService, - useClass: mockClass(RefreshSessionService), - }, - { provide: UrlService, useClass: mockClass(UrlService) }, - { - provide: AuthWellKnownService, - useClass: mockClass(AuthWellKnownService), - }, + mockProvider(CheckSessionService), + mockProvider(CheckAuthService), + mockProvider(UserService), + mockProvider(TokenHelperService), + mockProvider(ConfigurationService), + mockProvider(AuthStateService), + mockProvider(FlowsDataService), + mockProvider(CallbackService), + mockProvider(LogoffRevocationService), + mockProvider(LoginService), + mockProvider(RefreshSessionService), + mockProvider(UrlService), + mockProvider(AuthWellKnownService), ], }); }); @@ -147,7 +121,7 @@ describe('OidcSecurityService', () => { const spy = spyOnProperty( callbackService, 'stsCallback$' - ).and.returnValue(of({ some: 'data' })); + ).and.returnValue(of()); oidcSecurityService.stsCallback$.subscribe(() => { expect(spy).toHaveBeenCalledTimes(1); @@ -165,7 +139,7 @@ describe('OidcSecurityService', () => { const spy = spyOn( authWellKnownService, 'queryAndStoreAuthWellKnownEndPoints' - ).and.returnValue(of(null)); + ).and.returnValue(of({})); oidcSecurityService.preloadAuthWellKnownDocument().subscribe(() => { expect(spy).toHaveBeenCalledOnceWith(config); @@ -248,7 +222,7 @@ describe('OidcSecurityService', () => { ); const spy = spyOn(checkAuthService, 'checkAuth').and.returnValue( - of(null) + of({} as LoginResponse) ); oidcSecurityService.checkAuth().subscribe(() => { @@ -264,7 +238,7 @@ describe('OidcSecurityService', () => { ); const spy = spyOn(checkAuthService, 'checkAuth').and.returnValue( - of(null) + of({} as LoginResponse) ); oidcSecurityService.checkAuth('some-url').subscribe(() => { @@ -282,7 +256,7 @@ describe('OidcSecurityService', () => { ); const spy = spyOn(checkAuthService, 'checkAuthMultiple').and.returnValue( - of(null) + of([{}] as LoginResponse[]) ); oidcSecurityService.checkAuthMultiple().subscribe(() => { @@ -298,7 +272,7 @@ describe('OidcSecurityService', () => { ); const spy = spyOn(checkAuthService, 'checkAuthMultiple').and.returnValue( - of(null) + of([{}] as LoginResponse[]) ); oidcSecurityService.checkAuthMultiple('some-url').subscribe(() => { @@ -336,7 +310,7 @@ describe('OidcSecurityService', () => { const spy = spyOn( checkAuthService, 'checkAuthIncludingServer' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as LoginResponse)); oidcSecurityService.checkAuthIncludingServer().subscribe(() => { expect(spy).toHaveBeenCalledOnceWith(config, [config]); @@ -562,7 +536,7 @@ describe('OidcSecurityService', () => { of({ allConfigs: [config], currentConfig: config }) ); const spy = spyOn(loginService, 'loginWithPopUp').and.callFake(() => - of(null) + of({} as LoginResponse) ); oidcSecurityService.authorizeWithPopUp().subscribe(() => { @@ -587,7 +561,7 @@ describe('OidcSecurityService', () => { const spy = spyOn( refreshSessionService, 'userForceRefreshSession' - ).and.returnValue(of(null)); + ).and.returnValue(of({} as LoginResponse)); oidcSecurityService.forceRefreshSession().subscribe(() => { expect(spy).toHaveBeenCalledOnceWith(config, [config], undefined); diff --git a/projects/angular-auth-oidc-client/src/lib/oidc.security.service.ts b/projects/angular-auth-oidc-client/src/lib/oidc.security.service.ts index eceda94e6..8760fc4c7 100644 --- a/projects/angular-auth-oidc-client/src/lib/oidc.security.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/oidc.security.service.ts @@ -59,7 +59,7 @@ export class OidcSecurityService { /** * Emits on a Security Token Service callback. The observable will never contain a value. */ - get stsCallback$(): Observable { + get stsCallback$(): Observable { return this.callbackService.stsCallback$; } @@ -105,7 +105,7 @@ export class OidcSecurityService { * * @param configId The configId to identify the config. If not passed, the first one is being returned */ - getConfiguration(configId?: string): Observable { + getConfiguration(configId?: string): Observable { return this.configurationService.getOpenIDConfiguration(configId); } @@ -235,7 +235,7 @@ export class OidcSecurityService { * * @returns A object with the authentication result */ - getAuthenticationResult(configId?: string): Observable { + getAuthenticationResult(configId?: string): Observable { return this.configurationService .getOpenIDConfiguration(configId) .pipe( diff --git a/projects/angular-auth-oidc-client/src/lib/provide-auth.spec.ts b/projects/angular-auth-oidc-client/src/lib/provide-auth.spec.ts index ca38fa28b..06d0bfe2c 100644 --- a/projects/angular-auth-oidc-client/src/lib/provide-auth.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/provide-auth.spec.ts @@ -1,6 +1,6 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { of } from 'rxjs'; -import { mockClass } from '../test/auto-mock'; +import { mockProvider } from '../test/auto-mock'; import { PASSED_CONFIG } from './auth-config'; import { ConfigurationService } from './config/config.service'; import { @@ -18,10 +18,7 @@ describe('provideAuth', () => { TestBed.configureTestingModule({ providers: [ provideAuth({ config: { authority: 'something' } }), - { - provide: ConfigurationService, - useClass: mockClass(ConfigurationService), - }, + mockProvider(ConfigurationService), ], }).compileComponents(); })); @@ -45,13 +42,10 @@ describe('provideAuth', () => { provideAuth({ loader: { provide: StsConfigLoader, - useFactory: () => new StsConfigHttpLoader(of(null)), + useFactory: () => new StsConfigHttpLoader(of({})), }, }), - { - provide: ConfigurationService, - useClass: mockClass(ConfigurationService), - }, + mockProvider(ConfigurationService), ], }).compileComponents(); })); diff --git a/projects/angular-auth-oidc-client/src/lib/public-events/event-types.ts b/projects/angular-auth-oidc-client/src/lib/public-events/event-types.ts index 7663fde31..54f35a95a 100644 --- a/projects/angular-auth-oidc-client/src/lib/public-events/event-types.ts +++ b/projects/angular-auth-oidc-client/src/lib/public-events/event-types.ts @@ -1,4 +1,3 @@ -// eslint-disable-next-line no-shadow export enum EventTypes { /** * This only works in the AppModule Constructor diff --git a/projects/angular-auth-oidc-client/src/lib/storage/browser-storage.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/storage/browser-storage.service.spec.ts index a1ed516df..e40c86e26 100644 --- a/projects/angular-auth-oidc-client/src/lib/storage/browser-storage.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/storage/browser-storage.service.spec.ts @@ -1,23 +1,22 @@ import { TestBed } from '@angular/core/testing'; -import { mockClass } from '../../test/auto-mock'; +import { mockClass, mockProvider } from '../../test/auto-mock'; import { LoggerService } from '../logging/logger.service'; import { AbstractSecurityStorage } from './abstract-security-storage'; import { BrowserStorageService } from './browser-storage.service'; import { DefaultSessionStorageService } from './default-sessionstorage.service'; -describe('Browser Service', () => { +describe('BrowserStorageService', () => { let service: BrowserStorageService; let abstractSecurityStorage: AbstractSecurityStorage; beforeEach(() => { TestBed.configureTestingModule({ providers: [ + mockProvider(LoggerService), { provide: AbstractSecurityStorage, useClass: mockClass(DefaultSessionStorageService), }, - BrowserStorageService, - { provide: LoggerService, useClass: mockClass(LoggerService) }, ], }); }); @@ -161,7 +160,7 @@ describe('Browser Service', () => { describe('hasStorage', () => { it('returns false if there is no storage', () => { - Storage = undefined; + (Storage as any) = undefined; expect((service as any).hasStorage()).toBeFalse(); Storage = Storage; }); diff --git a/projects/angular-auth-oidc-client/src/lib/storage/browser-storage.service.ts b/projects/angular-auth-oidc-client/src/lib/storage/browser-storage.service.ts index 136649b3b..06a510a47 100644 --- a/projects/angular-auth-oidc-client/src/lib/storage/browser-storage.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/storage/browser-storage.service.ts @@ -13,6 +13,15 @@ export class BrowserStorageService { read(key: string, configuration: OpenIdConfiguration): any { const { configId } = configuration; + if (!configId) { + this.loggerService.logDebug( + configuration, + `Wanted to read '${key}' but configId was '${configId}'` + ); + + return null; + } + if (!this.hasStorage()) { this.loggerService.logDebug( configuration, @@ -34,10 +43,19 @@ export class BrowserStorageService { write(value: any, configuration: OpenIdConfiguration): boolean { const { configId } = configuration; + if (!configId) { + this.loggerService.logDebug( + configuration, + `Wanted to write but configId was '${configId}'` + ); + + return false; + } + if (!this.hasStorage()) { this.loggerService.logDebug( configuration, - `Wanted to write '${value}' but Storage was falsy` + `Wanted to write but Storage was falsy` ); return false; diff --git a/projects/angular-auth-oidc-client/src/lib/storage/storage-persistence.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/storage/storage-persistence.service.spec.ts index 573213d5a..204fee1ab 100644 --- a/projects/angular-auth-oidc-client/src/lib/storage/storage-persistence.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/storage/storage-persistence.service.spec.ts @@ -1,5 +1,5 @@ import { TestBed } from '@angular/core/testing'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { BrowserStorageService } from './browser-storage.service'; import { StoragePersistenceService } from './storage-persistence.service'; @@ -9,13 +9,7 @@ describe('Storage Persistence Service', () => { beforeEach(() => { TestBed.configureTestingModule({ - providers: [ - StoragePersistenceService, - { - provide: BrowserStorageService, - useClass: mockClass(BrowserStorageService), - }, - ], + providers: [mockProvider(BrowserStorageService)], }); }); @@ -93,7 +87,7 @@ describe('Storage Persistence Service', () => { it('should call oidcSecurityStorage.clear()', () => { const clearSpy = spyOn(securityStorage, 'clear'); - service.clear(null); + service.clear({}); expect(clearSpy).toHaveBeenCalledTimes(1); }); diff --git a/projects/angular-auth-oidc-client/src/lib/user-data/user-service.spec.ts b/projects/angular-auth-oidc-client/src/lib/user-data/user-service.spec.ts index 874a61186..1ff7a2ec6 100644 --- a/projects/angular-auth-oidc-client/src/lib/user-data/user-service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/user-data/user-service.spec.ts @@ -1,6 +1,6 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { Observable, of, throwError } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { createRetriableStream } from '../../test/create-retriable-stream.helper'; import { DataService } from '../api/data.service'; import { OpenIdConfiguration } from '../config/openid-configuration'; @@ -29,16 +29,12 @@ describe('User Service', () => { beforeEach(() => { TestBed.configureTestingModule({ providers: [ - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - { provide: DataService, useClass: mockClass(DataService) }, - { provide: PlatformProvider, useClass: mockClass(PlatformProvider) }, + mockProvider(StoragePersistenceService), + mockProvider(LoggerService), + mockProvider(DataService), + mockProvider(PlatformProvider), PublicEventsService, TokenHelperService, - UserService, FlowHelper, ], }); @@ -535,7 +531,7 @@ describe('User Service', () => { .withArgs('authWellKnownEndPoints', config) .and.returnValue(null); serviceAsAny.getIdentityUserData(config).subscribe({ - error: (err) => { + error: (err: any) => { expect(err).toBeTruthy(); }, }); @@ -552,7 +548,7 @@ describe('User Service', () => { .withArgs('authWellKnownEndPoints', config) .and.returnValue({ userInfoEndpoint: null }); serviceAsAny.getIdentityUserData(config).subscribe({ - error: (err) => { + error: (err: any) => { expect(err).toBeTruthy(); }, }); @@ -596,7 +592,7 @@ describe('User Service', () => { ); (userService as any).getIdentityUserData(config).subscribe({ - next: (res) => { + next: (res: any) => { expect(res).toBeTruthy(); expect(res).toEqual(DUMMY_USER_DATA); }, @@ -621,7 +617,7 @@ describe('User Service', () => { ); (userService as any).getIdentityUserData(config).subscribe({ - next: (res) => { + next: (res: any) => { expect(res).toBeTruthy(); expect(res).toEqual(DUMMY_USER_DATA); }, @@ -647,7 +643,7 @@ describe('User Service', () => { ); (userService as any).getIdentityUserData(config).subscribe({ - error: (err) => { + error: (err: any) => { expect(err).toBeTruthy(); }, }); diff --git a/projects/angular-auth-oidc-client/src/lib/user-data/user.service.ts b/projects/angular-auth-oidc-client/src/lib/user-data/user.service.ts index ba7a397a1..e44feaddf 100644 --- a/projects/angular-auth-oidc-client/src/lib/user-data/user.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/user-data/user.service.ts @@ -108,7 +108,16 @@ export class UserService { return of(existingUserDataFromStorage); } - getUserDataFromStore(currentConfiguration: OpenIdConfiguration): any { + getUserDataFromStore(currentConfiguration: OpenIdConfiguration | null): any { + if (!currentConfiguration) { + return throwError( + () => + new Error( + 'Please provide a configuration before setting up the module' + ) + ); + } + return ( this.storagePersistenceService.read('userData', currentConfiguration) || null @@ -274,20 +283,24 @@ export class UserService { if (!hasManyConfigs) { const { configId } = currentConfiguration; - return this.composeSingleUserDataResult(configId, passedUserData); + return this.composeSingleUserDataResult(configId ?? '', passedUserData); } const allUserData: ConfigUserDataResult[] = allConfigs.map((config) => { - const { configId } = currentConfiguration; + const currentConfigId = currentConfiguration.configId ?? ''; + const configId = config.configId ?? ''; - if (this.currentConfigIsToUpdate(configId, config)) { - return { configId: config.configId, userData: passedUserData }; + if (this.currentConfigIsToUpdate(currentConfigId, config)) { + return { configId, userData: passedUserData }; } const alreadySavedUserData = this.storagePersistenceService.read('userData', config) || null; - return { configId: config.configId, userData: alreadySavedUserData }; + return { + configId, + userData: alreadySavedUserData, + }; }); return { diff --git a/projects/angular-auth-oidc-client/src/lib/utils/collections/collections.helper.ts b/projects/angular-auth-oidc-client/src/lib/utils/collections/collections.helper.ts new file mode 100644 index 000000000..f83619f99 --- /dev/null +++ b/projects/angular-auth-oidc-client/src/lib/utils/collections/collections.helper.ts @@ -0,0 +1,7 @@ +export function flattenArray(array: any[][]): any[] { + return array.reduce( + (flattened, elem) => + flattened.concat(Array.isArray(elem) ? flattenArray(elem) : elem), + [] + ); +} diff --git a/projects/angular-auth-oidc-client/src/lib/utils/crypto/crypto.service.ts b/projects/angular-auth-oidc-client/src/lib/utils/crypto/crypto.service.ts index a41daf5cb..782834d56 100644 --- a/projects/angular-auth-oidc-client/src/lib/utils/crypto/crypto.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/utils/crypto/crypto.service.ts @@ -8,7 +8,7 @@ export class CryptoService { getCrypto(): any { // support for IE, (window.crypto || window.msCrypto) return ( - this.doc.defaultView.crypto || (this.doc.defaultView as any).msCrypto + this.doc.defaultView?.crypto || (this.doc.defaultView as any)?.msCrypto ); } } diff --git a/projects/angular-auth-oidc-client/src/lib/utils/equality/equality.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/utils/equality/equality.service.spec.ts index 54079e024..98f18f782 100644 --- a/projects/angular-auth-oidc-client/src/lib/utils/equality/equality.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/utils/equality/equality.service.spec.ts @@ -154,21 +154,6 @@ describe('EqualityService Tests', () => { input2: 'value1', expected: true, }, - { - input1: null, - input2: 'value2', - expected: false, - }, - { - input1: 'value1', - input2: null, - expected: false, - }, - { - input1: null, - input2: null, - expected: false, - }, { input1: 'value1', input2: 'value2', @@ -177,42 +162,42 @@ describe('EqualityService Tests', () => { // old "x" (string) , [x] new invalid { input1: 'value1', - input2: ['value2'], + input2: ['value2'] as any[], expected: false, }, // old [x], new "x" (string) invalid { - input1: ['value2'], + input1: ['value2'] as any[], input2: 'value1', expected: false, }, { - input1: ['value1'], - input2: ['value2'], + input1: ['value1'] as any[], + input2: ['value2'] as any[], expected: false, }, // old [x,y,z], new [x,y] invalid // old [x], new [y,x] invalid { - input1: ['value1'], - input2: ['value1', 'value2'], + input1: ['value1'] as any[], + input2: ['value1', 'value2'] as any[], expected: false, }, { - input1: ['value1', 'value2'], - input2: ['value1', 'value2'], + input1: ['value1', 'value2'] as any[], + input2: ['value1', 'value2'] as any[], expected: true, }, // old [x,y], new [y,x] valid { - input1: ['value1', 'value2'], - input2: ['value2', 'value1'], + input1: ['value1', 'value2'] as any[], + input2: ['value2', 'value1'] as any[], expected: true, }, // old [x,y,z], new [y,z,x] valid { - input1: ['x', 'y', 'z'], - input2: ['y', 'z', 'x'], + input1: ['x', 'y', 'z'] as any[], + input2: ['y', 'z', 'x'] as any[], expected: true, }, ]; diff --git a/projects/angular-auth-oidc-client/src/lib/utils/flowHelper/flow-helper.service.ts b/projects/angular-auth-oidc-client/src/lib/utils/flowHelper/flow-helper.service.ts index d34737819..019208321 100644 --- a/projects/angular-auth-oidc-client/src/lib/utils/flowHelper/flow-helper.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/utils/flowHelper/flow-helper.service.ts @@ -15,11 +15,17 @@ export class FlowHelper { } isCurrentFlowCodeFlowWithRefreshTokens( - configuration: OpenIdConfiguration + configuration: OpenIdConfiguration | null ): boolean { + if (!configuration) { + return false; + } + const { useRefreshToken } = configuration; - return this.isCurrentFlowCodeFlow(configuration) && useRefreshToken; + return ( + this.isCurrentFlowCodeFlow(configuration) && Boolean(useRefreshToken) + ); } isCurrentFlowImplicitFlowWithAccessToken( diff --git a/projects/angular-auth-oidc-client/src/lib/utils/redirect/redirect.service.ts b/projects/angular-auth-oidc-client/src/lib/utils/redirect/redirect.service.ts index 16269ce2d..4888f0c90 100644 --- a/projects/angular-auth-oidc-client/src/lib/utils/redirect/redirect.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/utils/redirect/redirect.service.ts @@ -5,7 +5,7 @@ import { Inject, Injectable } from '@angular/core'; export class RedirectService { constructor(@Inject(DOCUMENT) private readonly document: Document) {} - redirectTo(url): void { + redirectTo(url: string): void { this.document.location.href = url; } } diff --git a/projects/angular-auth-oidc-client/src/lib/utils/tokenHelper/token-helper.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/utils/tokenHelper/token-helper.service.spec.ts index 8dc3ce581..d3ee296d9 100644 --- a/projects/angular-auth-oidc-client/src/lib/utils/tokenHelper/token-helper.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/utils/tokenHelper/token-helper.service.spec.ts @@ -1,5 +1,5 @@ import { TestBed } from '@angular/core/testing'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { LoggerService } from '../../logging/logger.service'; import { TokenHelperService } from './token-helper.service'; @@ -8,10 +8,7 @@ describe('Token Helper Service', () => { beforeEach(() => { TestBed.configureTestingModule({ - providers: [ - TokenHelperService, - { provide: LoggerService, useClass: mockClass(LoggerService) }, - ], + providers: [mockProvider(LoggerService)], }); }); diff --git a/projects/angular-auth-oidc-client/src/lib/utils/tokenHelper/token-helper.service.ts b/projects/angular-auth-oidc-client/src/lib/utils/tokenHelper/token-helper.service.ts index 7fb3463a6..acd67732a 100644 --- a/projects/angular-auth-oidc-client/src/lib/utils/tokenHelper/token-helper.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/utils/tokenHelper/token-helper.service.ts @@ -62,8 +62,12 @@ export class TokenHelperService { getPayloadFromToken( token: any, encoded: boolean, - configuration: OpenIdConfiguration + configuration: OpenIdConfiguration | null ): any { + if (!configuration) { + return {}; + } + if (!this.tokenIsValid(token, configuration)) { return {}; } @@ -113,9 +117,13 @@ export class TokenHelperService { const decoded = typeof this.document.defaultView !== 'undefined' - ? this.document.defaultView.atob(output) + ? this.document.defaultView?.atob(output) : Buffer.from(output, 'base64').toString('binary'); + if (!decoded) { + return ''; + } + try { // Going backwards: from byte stream, to percent-encoding, to original string. return decodeURIComponent( diff --git a/projects/angular-auth-oidc-client/src/lib/utils/url/current-url.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/utils/url/current-url.service.spec.ts index 35978db6c..8122059d2 100644 --- a/projects/angular-auth-oidc-client/src/lib/utils/url/current-url.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/utils/url/current-url.service.spec.ts @@ -5,21 +5,20 @@ import { CurrentUrlService } from './current-url.service'; describe('CurrentUrlService with existing Url', () => { let service: CurrentUrlService; + const documentValue = { + defaultView: { location: 'http://my-url.com?state=my-state' }, + }; + beforeEach(() => { TestBed.configureTestingModule({ providers: [ - CurrentUrlService, { provide: DOCUMENT, - useValue: { - defaultView: { location: 'http://my-url.com?state=my-state' }, - }, + useValue: documentValue, }, ], }); - }); - beforeEach(() => { service = TestBed.inject(CurrentUrlService); }); @@ -36,6 +35,14 @@ describe('CurrentUrlService with existing Url', () => { }); describe('getStateParamFromCurrentUrl', () => { + it('returns null if there is no current URL', () => { + spyOn(service, 'getCurrentUrl').and.returnValue(null); + + const stateParam = service.getStateParamFromCurrentUrl(''); + + expect(stateParam).toBe(null); + }); + it('returns the state param for the URL', () => { const stateParam = service.getStateParamFromCurrentUrl(); @@ -57,7 +64,7 @@ describe('CurrentUrlService with existing Url', () => { }); it('returns the state param for the URL if one is passed as null', () => { - const stateParam = service.getStateParamFromCurrentUrl(null); + const stateParam = service.getStateParamFromCurrentUrl(undefined); expect(stateParam).toBe('my-state'); }); diff --git a/projects/angular-auth-oidc-client/src/lib/utils/url/current-url.service.ts b/projects/angular-auth-oidc-client/src/lib/utils/url/current-url.service.ts index cde0b0283..607d5f470 100644 --- a/projects/angular-auth-oidc-client/src/lib/utils/url/current-url.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/utils/url/current-url.service.ts @@ -1,19 +1,24 @@ import { DOCUMENT } from '@angular/common'; -import { Inject, Injectable } from '@angular/core'; +import { Injectable, inject } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class CurrentUrlService { - constructor(@Inject(DOCUMENT) private readonly document: Document) {} + private readonly document: Document = inject(DOCUMENT); - getStateParamFromCurrentUrl(url?: string): string { + getStateParamFromCurrentUrl(url?: string): string | null { const currentUrl = url || this.getCurrentUrl(); + + if (!currentUrl) { + return null; + } + const parsedUrl = new URL(currentUrl); const urlParams = new URLSearchParams(parsedUrl.search); return urlParams.get('state'); } - getCurrentUrl(): string { - return this.document.defaultView.location.toString(); + getCurrentUrl(): string | null { + return this.document?.defaultView?.location.toString() ?? null; } } diff --git a/projects/angular-auth-oidc-client/src/lib/utils/url/url.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/utils/url/url.service.spec.ts index 49e7434fd..3be9d0cc2 100644 --- a/projects/angular-auth-oidc-client/src/lib/utils/url/url.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/utils/url/url.service.spec.ts @@ -1,6 +1,6 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { of } from 'rxjs'; -import { mockClass } from '../../../test/auto-mock'; +import { mockProvider } from '../../../test/auto-mock'; import { OpenIdConfiguration } from '../../config/openid-configuration'; import { FlowsDataService } from '../../flows/flows-data.service'; import { LoggerService } from '../../logging/logger.service'; @@ -21,23 +21,11 @@ describe('UrlService Tests', () => { TestBed.configureTestingModule({ providers: [ UrlService, - { - provide: LoggerService, - useClass: mockClass(LoggerService), - }, - { - provide: FlowsDataService, - useClass: mockClass(FlowsDataService), - }, + mockProvider(LoggerService), + mockProvider(FlowsDataService), FlowHelper, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, - { - provide: JwtWindowCryptoService, - useClass: mockClass(JwtWindowCryptoService), - }, + mockProvider(StoragePersistenceService), + mockProvider(JwtWindowCryptoService), ], }); }); @@ -165,7 +153,7 @@ describe('UrlService Tests', () => { }); describe('createAuthorizeUrl', () => { - it('returns null when no authoizationendpoint given -> wellKnownEndpoints null', () => { + it('returns empty string when no authoizationendpoint given -> wellKnownEndpoints null', () => { const value = (service as any).createAuthorizeUrl( '', // Implicit Flow 'https://localhost:44386', @@ -173,12 +161,10 @@ describe('UrlService Tests', () => { 'state' ); - const expectValue = null; - - expect(value).toEqual(expectValue); + expect(value).toEqual(''); }); - it('returns null when no authoizationendpoint given -> configurationProvider null', () => { + it('returns empty string when no authoizationendpoint given -> configurationProvider null', () => { (service as any).configurationProvider = null; const value = (service as any).createAuthorizeUrl( @@ -188,13 +174,11 @@ describe('UrlService Tests', () => { 'state' ); - const expectValue = null; - - expect(value).toEqual(expectValue); + expect(value).toEqual(''); }); - it('returns null when clientId is null', () => { - const config = { configId: 'configId1', clientId: null }; + it('returns empty string when clientId is null', () => { + const config = { configId: 'configId1', clientId: '' }; const authorizationEndpoint = 'authorizationEndpoint'; spyOn(storagePersistenceService, 'read') @@ -209,16 +193,14 @@ describe('UrlService Tests', () => { config ); - const expectValue = null; - - expect(value).toEqual(expectValue); + expect(value).toEqual(''); }); - it('returns null when responseType is null', () => { + it('returns empty string when responseType is null', () => { const config = { configId: 'configId1', clientId: 'something', - responseType: null, + responseType: undefined, }; const authorizationEndpoint = 'authorizationEndpoint'; @@ -234,17 +216,15 @@ describe('UrlService Tests', () => { config ); - const expectValue = null; - - expect(value).toEqual(expectValue); + expect(value).toEqual(''); }); - it('returns null when scope is null', () => { + it('returns empty string when scope is null', () => { const config = { configId: 'configId1', clientId: 'something', responseType: 'responsetype', - scope: null, + scope: undefined, }; const authorizationEndpoint = 'authorizationEndpoint'; @@ -260,9 +240,7 @@ describe('UrlService Tests', () => { config ); - const expectValue = null; - - expect(value).toEqual(expectValue); + expect(value).toEqual(''); }); it('createAuthorizeUrl with code flow and codeChallenge adds "code_challenge" and "code_challenge_method" param', () => { @@ -563,7 +541,7 @@ describe('UrlService Tests', () => { '188968487735-b1hh7k87nkkh6vv84548sinju2kpr7gn.apps.googleusercontent.com', responseType: 'id_token token', scope: 'openid email profile', - customParamsAuthRequest: null, + customParamsAuthRequest: undefined, configId: 'configId1', }; @@ -786,7 +764,7 @@ describe('UrlService Tests', () => { it('createRevocationEndpointBodyAccessToken returns null when no clientId is given', () => { const config = { authority: 'https://localhost:5001', - clientId: null, + clientId: '', } as OpenIdConfiguration; const value = service.createRevocationEndpointBodyAccessToken( 'mytoken', @@ -831,7 +809,7 @@ describe('UrlService Tests', () => { it('createRevocationEndpointBodyRefreshToken returns null when no clientId is given', () => { const config = { authority: 'https://localhost:5001', - clientId: null, + clientId: undefined, } as OpenIdConfiguration; const value = service.createRevocationEndpointBodyRefreshToken( 'mytoken', @@ -899,17 +877,17 @@ describe('UrlService Tests', () => { it('getRevocationEndpointUrl returns null when there is not revociationendpoint given', () => { spyOn(storagePersistenceService, 'read') - .withArgs('authWellKnownEndPoints', null) + .withArgs('authWellKnownEndPoints', {}) .and.returnValue({ revocationEndpoint: null, }); - const value = service.getRevocationEndpointUrl(null); + const value = service.getRevocationEndpointUrl({}); expect(value).toBeNull(); }); it('getRevocationEndpointUrl returns null when there is no wellKnownEndpoints given', () => { - const value = service.getRevocationEndpointUrl(null); + const value = service.getRevocationEndpointUrl({}); expect(value).toBeNull(); }); @@ -934,6 +912,12 @@ describe('UrlService Tests', () => { }); describe('getAuthorizeUrl', () => { + it('returns null if no config is given', waitForAsync(() => { + service.getAuthorizeUrl(null).subscribe((url) => { + expect(url).toBeNull(); + }); + })); + it('returns null if current flow is code flow and no redirect url is defined', waitForAsync(() => { spyOn(flowHelper, 'isCurrentFlowCodeFlow').and.returnValue(true); @@ -964,8 +948,8 @@ describe('UrlService Tests', () => { clientId: 'some-clientId', responseType: 'testResponseType', scope: 'testScope', - hdParam: null, - customParamsAuthRequest: null, + hdParam: undefined, + customParamsAuthRequest: undefined, } as OpenIdConfiguration; const authorizationEndpoint = 'authorizationEndpoint'; @@ -1073,7 +1057,7 @@ describe('UrlService Tests', () => { const codeVerifier = 'codeverifier'; spyOn(flowsDataService, 'getCodeVerifier').and.returnValue(codeVerifier); - const clientId = null; + const clientId = ''; const result = service.createBodyForCodeFlowCodeRequest( 'notRelevantParam', { clientId } @@ -1085,7 +1069,7 @@ describe('UrlService Tests', () => { it('returns null if silentrenewRunning is false and redirectUrl is falsy', () => { const codeVerifier = 'codeverifier'; const code = 'code'; - const redirectUrl = null; + const redirectUrl = ''; const clientId = 'clientId'; spyOn(flowsDataService, 'getCodeVerifier').and.returnValue(codeVerifier); @@ -1237,8 +1221,8 @@ describe('UrlService Tests', () => { clientId: 'testClientId', responseType: 'testResponseType', scope: 'testScope', - hdParam: null, - customParamsAuthRequest: null, + hdParam: undefined, + customParamsAuthRequest: undefined, redirectUrl: 'testRedirectUrl', }; @@ -1269,7 +1253,7 @@ describe('UrlService Tests', () => { responseType: 'testResponseType', scope: 'testScope', hdParam: 'testHdParam', - customParamsAuthRequest: null, + customParamsAuthRequest: undefined, redirectUrl: 'testRedirectUrl', }; @@ -1478,7 +1462,7 @@ describe('UrlService Tests', () => { const resultObs$ = serviceAsAny.createUrlCodeFlowWithSilentRenew(config); - resultObs$.subscribe((result) => { + resultObs$.subscribe((result: any) => { expect(result).toBe(''); }); })); @@ -1520,7 +1504,7 @@ describe('UrlService Tests', () => { const resultObs$ = serviceAsAny.createUrlCodeFlowWithSilentRenew(config); - resultObs$.subscribe((result) => { + resultObs$.subscribe((result: any) => { expect(result).toBe( `authorizationEndpoint?client_id=${clientId}&redirect_uri=http%3A%2F%2Fany-url.com&response_type=${responseType}&scope=${scope}&nonce=${nonce}&state=${state}&prompt=none` ); @@ -1560,8 +1544,8 @@ describe('UrlService Tests', () => { const resultObs$ = serviceAsAny.createUrlCodeFlowWithSilentRenew(config); - resultObs$.subscribe((result) => { - expect(result).toBe(null); + resultObs$.subscribe((result: any) => { + expect(result).toBe(''); }); })); }); @@ -1670,7 +1654,7 @@ describe('UrlService Tests', () => { const resultObs$ = serviceAsAny.createUrlCodeFlowAuthorize(config); - resultObs$.subscribe((result) => { + resultObs$.subscribe((result: any) => { expect(result).toBeNull(); }); })); @@ -1711,7 +1695,7 @@ describe('UrlService Tests', () => { const resultObs$ = serviceAsAny.createUrlCodeFlowAuthorize(config); - resultObs$.subscribe((result) => { + resultObs$.subscribe((result: any) => { expect(result).toBe( `authorizationEndpoint?client_id=clientId&redirect_uri=http%3A%2F%2Fany-url.com&response_type=${responseType}&scope=${scope}&nonce=${nonce}&state=${state}` ); @@ -1759,7 +1743,7 @@ describe('UrlService Tests', () => { customParams: { to: 'add', as: 'well' }, }); - resultObs$.subscribe((result) => { + resultObs$.subscribe((result: any) => { expect(result).toBe( `authorizationEndpoint?client_id=clientId&redirect_uri=http%3A%2F%2Fany-url.com` + `&response_type=${responseType}&scope=${scope}&nonce=${nonce}&state=${state}&to=add&as=well` @@ -1796,13 +1780,19 @@ describe('UrlService Tests', () => { const resultObs$ = serviceAsAny.createUrlCodeFlowAuthorize(config); - resultObs$.subscribe((result) => { + resultObs$.subscribe((result: any) => { expect(result).toBe(''); }); })); }); describe('getEndSessionUrl', () => { + it('returns null if no config given', () => { + const value = service.getEndSessionUrl(null); + + expect(value).toBeNull(); + }); + it('create URL when all parameters given', () => { //Arrange const config = { @@ -1832,7 +1822,7 @@ describe('UrlService Tests', () => { postLogoutRedirectUri: 'https://localhost:44386/Unauthorized', } as OpenIdConfiguration; - spyOn(storagePersistenceService, 'getIdToken').and.returnValue(null); + spyOn(storagePersistenceService, 'getIdToken').and.returnValue(''); spyOn(storagePersistenceService, 'read') .withArgs('authWellKnownEndPoints', config) .and.returnValue({ @@ -1903,7 +1893,7 @@ describe('UrlService Tests', () => { it('create URL without postLogoutRedirectUri when not given', () => { const config = { - postLogoutRedirectUri: null, + postLogoutRedirectUri: '', } as OpenIdConfiguration; spyOn(storagePersistenceService, 'read') @@ -1980,7 +1970,7 @@ describe('UrlService Tests', () => { }); it('returns null if configurationProvider.openIDConfiguration has no clientId', () => { - const config = { clientId: null }; + const config = { clientId: '' } as OpenIdConfiguration; spyOn(storagePersistenceService, 'read') .withArgs('authWellKnownEndPoints', config) diff --git a/projects/angular-auth-oidc-client/src/lib/utils/url/url.service.ts b/projects/angular-auth-oidc-client/src/lib/utils/url/url.service.ts index b602e48ca..2e7bce5f4 100644 --- a/projects/angular-auth-oidc-client/src/lib/utils/url/url.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/utils/url/url.service.ts @@ -1,5 +1,5 @@ import { HttpParams } from '@angular/common/http'; -import { Injectable } from '@angular/core'; +import { Injectable, inject } from '@angular/core'; import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; import { AuthOptions } from '../../auth-options'; @@ -16,13 +16,17 @@ const AUTH0_ENDPOINT = 'auth0.com'; @Injectable({ providedIn: 'root' }) export class UrlService { - constructor( - private readonly loggerService: LoggerService, - private readonly flowsDataService: FlowsDataService, - private readonly flowHelper: FlowHelper, - private readonly storagePersistenceService: StoragePersistenceService, - private readonly jwtWindowCryptoService: JwtWindowCryptoService - ) {} + private readonly loggerService = inject(LoggerService); + + private readonly flowsDataService = inject(FlowsDataService); + + private readonly flowHelper = inject(FlowHelper); + + private readonly storagePersistenceService = inject( + StoragePersistenceService + ); + + private readonly jwtWindowCryptoService = inject(JwtWindowCryptoService); getUrlParameter(urlToCheck: string, name: string): string { if (!urlToCheck) { @@ -49,20 +53,18 @@ export class UrlService { getRefreshSessionSilentRenewUrl( config: OpenIdConfiguration, customParams?: { [key: string]: string | number | boolean } - ): Observable { + ): Observable { if (this.flowHelper.isCurrentFlowCodeFlow(config)) { return this.createUrlCodeFlowWithSilentRenew(config, customParams); } - return of( - this.createUrlImplicitFlowWithSilentRenew(config, customParams) || '' - ); + return of(this.createUrlImplicitFlowWithSilentRenew(config, customParams)); } getAuthorizeParUrl( requestUri: string, configuration: OpenIdConfiguration - ): string { + ): string | null { const authWellKnownEndPoints = this.storagePersistenceService.read( 'authWellKnownEndPoints', configuration @@ -112,9 +114,13 @@ export class UrlService { } getAuthorizeUrl( - config: OpenIdConfiguration, + config: OpenIdConfiguration | null, authOptions?: AuthOptions - ): Observable { + ): Observable { + if (!config) { + return of(null); + } + if (this.flowHelper.isCurrentFlowCodeFlow(config)) { return this.createUrlCodeFlowAuthorize(config, authOptions); } @@ -150,9 +156,13 @@ export class UrlService { } getEndSessionUrl( - configuration: OpenIdConfiguration, + configuration: OpenIdConfiguration | null, customParams?: { [p: string]: string | number | boolean } ): string | null { + if (!configuration) { + return null; + } + const idToken = this.storagePersistenceService.getIdToken(configuration); const { customParamsEndSessionRequest } = configuration; const mergedParams = { ...customParamsEndSessionRequest, ...customParams }; @@ -163,7 +173,7 @@ export class UrlService { createRevocationEndpointBodyAccessToken( token: any, configuration: OpenIdConfiguration - ): string { + ): string | null { const clientId = this.getClientId(configuration); if (!clientId) { @@ -182,7 +192,7 @@ export class UrlService { createRevocationEndpointBodyRefreshToken( token: any, configuration: OpenIdConfiguration - ): string { + ): string | null { const clientId = this.getClientId(configuration); if (!clientId) { @@ -198,7 +208,7 @@ export class UrlService { return params.toString(); } - getRevocationEndpointUrl(configuration: OpenIdConfiguration): string { + getRevocationEndpointUrl(configuration: OpenIdConfiguration): string | null { const authWellKnownEndPoints = this.storagePersistenceService.read( 'authWellKnownEndPoints', configuration @@ -218,7 +228,7 @@ export class UrlService { code: string, configuration: OpenIdConfiguration, customTokenParams?: { [p: string]: string | number | boolean } - ): string { + ): string | null { const clientId = this.getClientId(configuration); if (!clientId) { @@ -278,7 +288,7 @@ export class UrlService { refreshToken: string, configuration: OpenIdConfiguration, customParamsRefresh?: { [key: string]: string | number | boolean } - ): string { + ): string | null { const clientId = this.getClientId(configuration); if (!clientId) { @@ -301,7 +311,7 @@ export class UrlService { createBodyForParCodeFlowRequest( configuration: OpenIdConfiguration, authOptions?: AuthOptions - ): Observable { + ): Observable { const redirectUrl = this.getRedirectUrl(configuration, authOptions); if (!redirectUrl) { @@ -332,10 +342,10 @@ export class UrlService { } = configuration; let params = this.createHttpParams(''); - params = params.set('client_id', clientId); + params = params.set('client_id', clientId ?? ''); params = params.append('redirect_uri', redirectUrl); - params = params.append('response_type', responseType); - params = params.append('scope', scope); + params = params.append('response_type', responseType ?? ''); + params = params.append('scope', scope ?? ''); params = params.append('nonce', nonce); params = params.append('state', state); params = params.append('code_challenge', codeChallenge); @@ -364,7 +374,7 @@ export class UrlService { ); } - getPostLogoutRedirectUrl(configuration: OpenIdConfiguration): string { + getPostLogoutRedirectUrl(configuration: OpenIdConfiguration): string | null { const { postLogoutRedirectUri } = configuration; if (!postLogoutRedirectUri) { @@ -438,7 +448,7 @@ export class UrlService { `Can not create an authorize URL when authorizationEndpoint is '${authorizationEndpoint}'` ); - return null; + return ''; } const { clientId, responseType, scope, hdParam, customParamsAuthRequest } = @@ -451,7 +461,7 @@ export class UrlService { clientId ); - return null; + return ''; } if (!responseType) { @@ -461,7 +471,7 @@ export class UrlService { responseType ); - return null; + return ''; } if (!scope) { @@ -471,7 +481,7 @@ export class UrlService { scope ); - return null; + return ''; } const urlParts = authorizationEndpoint.split('?'); @@ -486,10 +496,7 @@ export class UrlService { params = params.append('nonce', nonce); params = params.append('state', state); - if ( - this.flowHelper.isCurrentFlowCodeFlow(configuration) && - codeChallenge !== null - ) { + if (this.flowHelper.isCurrentFlowCodeFlow(configuration)) { params = params.append('code_challenge', codeChallenge); params = params.append('code_challenge_method', 'S256'); } @@ -514,7 +521,7 @@ export class UrlService { private createUrlImplicitFlowWithSilentRenew( configuration: OpenIdConfiguration, customParams?: { [key: string]: string | number | boolean } - ): string { + ): string | null { const state = this.flowsDataService.getExistingOrCreateAuthStateControl(configuration); const nonce = this.flowsDataService.createNonce(configuration); @@ -602,7 +609,7 @@ export class UrlService { 'authWellKnownEndpoints is undefined' ); - return null; + return ''; }) ); } @@ -610,7 +617,7 @@ export class UrlService { private createUrlImplicitFlowAuthorize( configuration: OpenIdConfiguration, authOptions?: AuthOptions - ): string { + ): string | null { const state = this.flowsDataService.getExistingOrCreateAuthStateControl(configuration); const nonce = this.flowsDataService.createNonce(configuration); @@ -640,7 +647,7 @@ export class UrlService { nonce, state, configuration, - null, + '', customParams ); } @@ -656,7 +663,7 @@ export class UrlService { private createUrlCodeFlowAuthorize( config: OpenIdConfiguration, authOptions?: AuthOptions - ): Observable { + ): Observable { const state = this.flowsDataService.getExistingOrCreateAuthStateControl(config); const nonce = this.flowsDataService.createNonce(config); @@ -688,7 +695,7 @@ export class UrlService { nonce, state, config, - null, + '', customParams ); } @@ -705,7 +712,7 @@ export class UrlService { private getCodeChallenge(config: OpenIdConfiguration): Observable { if (config.disablePkce) { - return of(null); + return of(''); } // code_challenge with "S256" @@ -717,7 +724,7 @@ export class UrlService { private getRedirectUrl( configuration: OpenIdConfiguration, authOptions?: AuthOptions - ): string { + ): string | null { let { redirectUrl } = configuration; if (authOptions?.redirectUrl) { @@ -738,7 +745,7 @@ export class UrlService { return redirectUrl; } - private getSilentRenewUrl(configuration: OpenIdConfiguration): string { + private getSilentRenewUrl(configuration: OpenIdConfiguration): string | null { const { silentRenewUrl } = configuration; if (!silentRenewUrl) { @@ -754,7 +761,7 @@ export class UrlService { return silentRenewUrl; } - private getClientId(configuration: OpenIdConfiguration): string { + private getClientId(configuration: OpenIdConfiguration): string | null { const { clientId } = configuration; if (!clientId) { @@ -805,7 +812,7 @@ export class UrlService { return false; } - return authority.endsWith(AUTH0_ENDPOINT) || useCustomAuth0Domain; + return authority.endsWith(AUTH0_ENDPOINT) || Boolean(useCustomAuth0Domain); } private composeAuth0Endpoint(configuration: OpenIdConfiguration): string { diff --git a/projects/angular-auth-oidc-client/src/lib/validation/jwk-window-crypto.service.ts b/projects/angular-auth-oidc-client/src/lib/validation/jwk-window-crypto.service.ts index 38b96cfd3..8654adbb2 100644 --- a/projects/angular-auth-oidc-client/src/lib/validation/jwk-window-crypto.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/validation/jwk-window-crypto.service.ts @@ -13,6 +13,7 @@ export class JwkWindowCryptoService { | EcKeyImportParams | HmacImportParams | AesKeyAlgorithm + | null ): Promise { return this.cryptoService .getCrypto() @@ -20,7 +21,7 @@ export class JwkWindowCryptoService { } verifyKey( - verifyAlgorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams, + verifyAlgorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams | null, cryptoKey: CryptoKey, signature: BufferSource, signingInput: string diff --git a/projects/angular-auth-oidc-client/src/lib/validation/jwt-window-crypto.service.ts b/projects/angular-auth-oidc-client/src/lib/validation/jwt-window-crypto.service.ts index 88e0374a5..403129741 100644 --- a/projects/angular-auth-oidc-client/src/lib/validation/jwt-window-crypto.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/validation/jwt-window-crypto.service.ts @@ -36,8 +36,9 @@ export class JwtWindowCryptoService { return from( this.cryptoService.getCrypto().subtle.digest(algorithm, msgBuffer) ).pipe( - map((hashBuffer: ArrayBuffer) => { - const hashArray: number[] = Array.from(new Uint8Array(hashBuffer)); + map((hashBuffer: unknown) => { + const buffer = hashBuffer as ArrayBuffer; + const hashArray: number[] = Array.from(new Uint8Array(buffer)); return this.toHashString(hashArray); }) @@ -54,7 +55,7 @@ export class JwtWindowCryptoService { return result; } - private base64UrlEncode(str): string { + private base64UrlEncode(str: string): string { const base64: string = btoa(str); return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); diff --git a/projects/angular-auth-oidc-client/src/lib/validation/state-validation.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/validation/state-validation.service.spec.ts index fcb4cacb5..331427126 100644 --- a/projects/angular-auth-oidc-client/src/lib/validation/state-validation.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/validation/state-validation.service.spec.ts @@ -1,8 +1,9 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { of } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { AuthWellKnownEndpoints } from '../config/auth-well-known/auth-well-known-endpoints'; import { OpenIdConfiguration } from '../config/openid-configuration'; +import { CallbackContext } from '../flows/callback-context'; import { LogLevel } from '../logging/log-level'; import { LoggerService } from '../logging/logger.service'; import { StoragePersistenceService } from '../storage/storage-persistence.service'; @@ -25,21 +26,10 @@ describe('State Validation Service', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [], providers: [ - StateValidationService, - { - provide: StoragePersistenceService, - useClass: mockClass(StoragePersistenceService), - }, - { - provide: TokenValidationService, - useClass: mockClass(TokenValidationService), - }, - { - provide: LoggerService, - useClass: mockClass(LoggerService), - }, + mockProvider(StoragePersistenceService), + mockProvider(TokenValidationService), + mockProvider(LoggerService), TokenHelperService, EqualityService, FlowHelper, @@ -698,7 +688,7 @@ describe('State Validation Service', () => { describe('getValidatedStateResult', () => { it('should return authResponseIsValid false when null is passed', waitForAsync(() => { const isValidObs$ = stateValidationService.getValidatedStateResult( - null, + {} as CallbackContext, config ); @@ -722,7 +712,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsggggggdfsdf', sessionState: 'fdffsggggggdfsdf', existingIdToken: null, @@ -809,7 +799,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsdfhhhhsdf', sessionState: 'fdffsggggggdfsdf', authResult: { @@ -858,7 +848,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsdfhhhhsdf', sessionState: 'fdffsggggggdfsdf', authResult: { @@ -951,7 +941,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsdfhhhhsdf', sessionState: 'fdffsggggggdfsdf', authResult: { @@ -1003,7 +993,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsdfhhhhsdf', sessionState: 'fdffsggggggdfsdf', authResult: { @@ -1065,7 +1055,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsdfhhhhsdf', sessionState: 'fdffsggggggdfsdf', authResult: { @@ -1132,7 +1122,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsdfhhhhsdf', sessionState: 'fdffsggggggdfsdf', authResult: { @@ -1206,7 +1196,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsdfhhhhsdf', sessionState: 'fdffsggggggdfsdf', authResult: { @@ -1283,7 +1273,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsdfhhhhsdf', sessionState: 'fdffsggggggdfsdf', authResult: { @@ -1348,7 +1338,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsdfhhhhsdf', sessionState: 'fdffsggggggdfsdf', authResult: { @@ -1423,7 +1413,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsdfhhhhsdf', sessionState: 'fdffsggggggdfsdf', authResult: { @@ -1498,7 +1488,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsdfhhhhsdf', sessionState: 'fdffsggggggdfsdf', authResult: { @@ -1577,7 +1567,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsdfhhhhsdf', sessionState: 'fdffsggggggdfsdf', authResult: { @@ -1660,7 +1650,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsdfhhhhsdf', sessionState: 'fdffsggggggdfsdf', authResult: { @@ -1754,7 +1744,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsdfhhhhsdf', sessionState: 'fdffsggggggdfsdf', authResult: { @@ -1852,7 +1842,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsdfhhhhsdf', sessionState: 'fdffsggggggdfsdf', authResult: { @@ -1943,7 +1933,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsdfhhhhsdf', sessionState: 'fdffsggggggdfsdf', authResult: { @@ -2022,7 +2012,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsdfhhhhsdf', sessionState: 'fdffsggggggdfsdf', authResult: { @@ -2065,7 +2055,7 @@ describe('State Validation Service', () => { const callbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsggggggdfsdf', sessionState: 'fdffsggggggdfsdf', existingIdToken: null, @@ -2101,12 +2091,12 @@ describe('State Validation Service', () => { config.maxIdTokenIatOffsetAllowedInSeconds = 0; config.disableIdTokenValidation = true; - const callbackContext = { + const callbackContext: CallbackContext = { code: 'fdffsdfsdf', - refreshToken: null, + refreshToken: '', state: 'fdffsggggggdfsdf', sessionState: 'fdffsggggggdfsdf', - existingIdToken: null, + existingIdToken: '', authResult: {}, isRenewProcess: false, jwtKeys: null, diff --git a/projects/angular-auth-oidc-client/src/lib/validation/state-validation.service.ts b/projects/angular-auth-oidc-client/src/lib/validation/state-validation.service.ts index cb8ca9802..a975cdf52 100644 --- a/projects/angular-auth-oidc-client/src/lib/validation/state-validation.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/validation/state-validation.service.ts @@ -27,7 +27,10 @@ export class StateValidationService { callbackContext: CallbackContext, configuration: OpenIdConfiguration ): Observable { - if (!callbackContext || callbackContext.authResult.error) { + const hasError = Boolean(callbackContext.authResult?.error); + const hasCallbackContext = Boolean(callbackContext); + + if (!hasCallbackContext || hasError) { return of(new StateValidationResult('', '', false, {})); } @@ -46,7 +49,7 @@ export class StateValidationService { if ( !this.tokenValidationService.validateStateFromHashCallback( - callbackContext.authResult.state, + callbackContext.authResult?.state, authStateControl, configuration ) @@ -67,14 +70,13 @@ export class StateValidationService { this.flowHelper.isCurrentFlowCodeFlow(configuration); if (isCurrentFlowImplicitFlowWithAccessToken || isCurrentFlowCodeFlow) { - toReturn.accessToken = callbackContext.authResult.access_token; + toReturn.accessToken = callbackContext.authResult?.access_token ?? ''; } const disableIdTokenValidation = configuration.disableIdTokenValidation; if (disableIdTokenValidation) { toReturn.state = ValidationResult.Ok; - // TODO TESTING toReturn.authResponseIsValid = true; return of(toReturn); @@ -82,17 +84,16 @@ export class StateValidationService { const isInRefreshTokenFlow = callbackContext.isRenewProcess && !!callbackContext.refreshToken; - const hasIdToken = !!callbackContext.authResult.id_token; + const hasIdToken = Boolean(callbackContext.authResult?.id_token); if (isInRefreshTokenFlow && !hasIdToken) { toReturn.state = ValidationResult.Ok; - // TODO TESTING toReturn.authResponseIsValid = true; return of(toReturn); } - if (callbackContext.authResult.id_token) { + if (hasIdToken) { const { clientId, issValidationOff, @@ -102,7 +103,7 @@ export class StateValidationService { renewTimeBeforeTokenExpiresInSeconds, } = configuration; - toReturn.idToken = callbackContext.authResult.id_token; + toReturn.idToken = callbackContext.authResult?.id_token ?? ''; toReturn.decodedIdToken = this.tokenHelperService.getPayloadFromToken( toReturn.idToken, false, @@ -137,7 +138,7 @@ export class StateValidationService { !this.tokenValidationService.validateIdTokenNonce( toReturn.decodedIdToken, authNonce, - ignoreNonceAfterRefresh, + Boolean(ignoreNonceAfterRefresh), configuration ) ) { @@ -171,8 +172,8 @@ export class StateValidationService { !isInRefreshTokenFlow && !this.tokenValidationService.validateIdTokenIatMaxOffset( toReturn.decodedIdToken, - maxIdTokenIatOffsetAllowedInSeconds, - disableIatOffsetValidation, + maxIdTokenIatOffsetAllowedInSeconds ?? 120, + Boolean(disableIatOffsetValidation), configuration ) ) { @@ -352,7 +353,7 @@ export class StateValidationService { } // only do check if id_token returned, no always the case when using refresh tokens - if (callbackContext.authResult.id_token) { + if (callbackContext.authResult?.id_token) { const idTokenHeader = this.tokenHelperService.getHeaderFromToken( toReturn.idToken, false, diff --git a/projects/angular-auth-oidc-client/src/lib/validation/token-validation.helper.ts b/projects/angular-auth-oidc-client/src/lib/validation/token-validation.helper.ts index 322cd050f..4bc993caa 100644 --- a/projects/angular-auth-oidc-client/src/lib/validation/token-validation.helper.ts +++ b/projects/angular-auth-oidc-client/src/lib/validation/token-validation.helper.ts @@ -1,4 +1,6 @@ -export function getVerifyAlg(alg: string): RsaHashedImportParams | EcdsaParams { +export function getVerifyAlg( + alg: string +): RsaHashedImportParams | EcdsaParams | null { switch (alg.charAt(0)) { case 'R': return { @@ -39,7 +41,7 @@ export function alg2kty(alg: string): string { export function getImportAlg( alg: string -): RsaHashedImportParams | EcKeyImportParams { +): RsaHashedImportParams | EcKeyImportParams | null { switch (alg.charAt(0)) { case 'R': if (alg.includes('256')) { diff --git a/projects/angular-auth-oidc-client/src/lib/validation/token-validation.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/validation/token-validation.service.spec.ts index 573de2fba..f2abacba2 100644 --- a/projects/angular-auth-oidc-client/src/lib/validation/token-validation.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/validation/token-validation.service.spec.ts @@ -1,6 +1,6 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { of } from 'rxjs'; -import { mockClass } from '../../test/auto-mock'; +import { mockProvider } from '../../test/auto-mock'; import { JwkExtractor } from '../extractors/jwk.extractor'; import { LoggerService } from '../logging/logger.service'; import { CryptoService } from '../utils/crypto/crypto.service'; @@ -19,14 +19,8 @@ describe('TokenValidationService', () => { imports: [], providers: [ TokenValidationService, - { - provide: LoggerService, - useClass: mockClass(LoggerService), - }, - { - provide: TokenHelperService, - useClass: mockClass(TokenHelperService), - }, + mockProvider(LoggerService), + mockProvider(TokenHelperService), JwkExtractor, JwkWindowCryptoService, JwtWindowCryptoService, @@ -518,7 +512,7 @@ describe('TokenValidationService', () => { it('returns true if no idToken is passed', waitForAsync(() => { const valueFalse$ = tokenValidationService.validateSignatureIdToken( - null, + null as any, 'some-jwt-keys', { configId: 'configId1' } ); @@ -776,7 +770,9 @@ describe('TokenValidationService', () => { describe('validateIdTokenExpNotExpired', () => { it('returns false when getTokenExpirationDate returns null', () => { - spyOn(tokenHelperService, 'getTokenExpirationDate').and.returnValue(null); + spyOn(tokenHelperService, 'getTokenExpirationDate').and.returnValue( + null as unknown as Date + ); const notExpired = tokenValidationService.validateIdTokenExpNotExpired( 'idToken', { configId: 'configId1' }, @@ -824,7 +820,7 @@ describe('TokenValidationService', () => { testCases.forEach(({ date, offsetSeconds, expectedResult }) => { it(`returns ${expectedResult} if ${date} is given with an offset of ${offsetSeconds}`, () => { const notExpired = tokenValidationService.validateAccessTokenNotExpired( - date, + date as Date, { configId: 'configId1' }, offsetSeconds ); diff --git a/projects/angular-auth-oidc-client/src/lib/validation/token-validation.service.ts b/projects/angular-auth-oidc-client/src/lib/validation/token-validation.service.ts index 08fdeafcc..4bea89d5a 100644 --- a/projects/angular-auth-oidc-client/src/lib/validation/token-validation.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/validation/token-validation.service.ts @@ -335,7 +335,7 @@ export class TokenValidationService { // not trusted by the Client. validateIdTokenAud( dataIdToken: any, - aud: any, + aud: string | undefined, configuration: OpenIdConfiguration ): boolean { if (Array.isArray(dataIdToken.aud)) { @@ -382,7 +382,10 @@ export class TokenValidationService { } // If an azp (authorized party) Claim is present, the Client SHOULD verify that its client_id is the Claim Value. - validateIdTokenAzpValid(dataIdToken: any, clientId: string): boolean { + validateIdTokenAzpValid( + dataIdToken: any, + clientId: string | undefined + ): boolean { if (!dataIdToken?.azp) { return true; } @@ -479,8 +482,7 @@ export class TokenValidationService { return of(false); } - const algorithm: RsaHashedImportParams | EcKeyImportParams = - getImportAlg(alg); + const algorithm = getImportAlg(alg); const signingInput = this.tokenHelperService.getSigningInputFromToken( idToken, @@ -501,8 +503,7 @@ export class TokenValidationService { loose: true, }); - const verifyAlgorithm: RsaHashedImportParams | EcdsaParams = - getVerifyAlg(alg); + const verifyAlgorithm = getVerifyAlg(alg); return from( this.jwkWindowCryptoService.verifyKey( diff --git a/projects/angular-auth-oidc-client/src/test/auto-mock.ts b/projects/angular-auth-oidc-client/src/test/auto-mock.ts index 5bae495ab..5cc7cbb57 100644 --- a/projects/angular-auth-oidc-client/src/test/auto-mock.ts +++ b/projects/angular-auth-oidc-client/src/test/auto-mock.ts @@ -1,3 +1,5 @@ +import { Provider } from '@angular/core'; + export function mockClass(obj: new (...args: any[]) => T): any { const keys = Object.getOwnPropertyNames(obj.prototype); const allMethods = keys.filter((key) => { @@ -12,8 +14,10 @@ export function mockClass(obj: new (...args: any[]) => T): any { const mockedClass = class T {}; allMethods.forEach( - // eslint-disable-next-line @typescript-eslint/no-empty-function - (method) => (mockedClass.prototype[method] = (): void => {}) + (method: string) => + ((mockedClass.prototype as any)[method] = (): void => { + return; + }) ); allProperties.forEach((method) => { @@ -27,3 +31,19 @@ export function mockClass(obj: new (...args: any[]) => T): any { return mockedClass; } + +export function mockProvider(obj: new (...args: any[]) => T): Provider { + return { + provide: obj, + useClass: mockClass(obj), + }; +} + +export function mockAbstractProvider( + type: abstract new (...args: any[]) => T, + mockType: new (...args: any[]) => M +): Provider { + const mock = mockClass(mockType); + + return { provide: type, useClass: mock }; +} diff --git a/projects/sample-code-flow-auth0/src/app/app.component.spec.ts b/projects/sample-code-flow-auth0/src/app/app.component.spec.ts index ca37aa2b0..7627c677e 100644 --- a/projects/sample-code-flow-auth0/src/app/app.component.spec.ts +++ b/projects/sample-code-flow-auth0/src/app/app.component.spec.ts @@ -11,19 +11,23 @@ describe('AppComponent', () => { it('should create the app', () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); }); it(`should have as title 'testSts'`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('testSts'); }); it('should render title in a h1 tag', () => { const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain( 'Welcome to testSts!' ); diff --git a/projects/sample-code-flow-auth0/src/app/app.component.ts b/projects/sample-code-flow-auth0/src/app/app.component.ts index 3d1a47b40..f24ea5510 100644 --- a/projects/sample-code-flow-auth0/src/app/app.component.ts +++ b/projects/sample-code-flow-auth0/src/app/app.component.ts @@ -8,7 +8,7 @@ import { OidcSecurityService } from 'angular-auth-oidc-client'; export class AppComponent implements OnInit { constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService .checkAuth() .subscribe(({ isAuthenticated }) => diff --git a/projects/sample-code-flow-auth0/src/app/home/home.component.ts b/projects/sample-code-flow-auth0/src/app/home/home.component.ts index 67cb6ab12..55499d3c9 100644 --- a/projects/sample-code-flow-auth0/src/app/home/home.component.ts +++ b/projects/sample-code-flow-auth0/src/app/home/home.component.ts @@ -1,28 +1,20 @@ import { Component, OnInit } from '@angular/core'; -import { - OidcClientNotification, - OidcSecurityService, - OpenIdConfiguration, - UserDataResult, -} from 'angular-auth-oidc-client'; -import { Observable } from 'rxjs'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-home', templateUrl: 'home.component.html', }) export class HomeComponent implements OnInit { - configuration$: Observable; - userDataChanged$: Observable>; - userData$: Observable; + configuration$ = this.oidcSecurityService.getConfiguration(); + + userData$ = this.oidcSecurityService.userData$; + isAuthenticated = false; constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { - this.configuration$ = this.oidcSecurityService.getConfiguration(); - this.userData$ = this.oidcSecurityService.userData$; - + ngOnInit(): void { this.oidcSecurityService.isAuthenticated$.subscribe( ({ isAuthenticated }) => { this.isAuthenticated = isAuthenticated; @@ -32,35 +24,35 @@ export class HomeComponent implements OnInit { ); } - login() { + login(): void { this.oidcSecurityService.authorize(); } - refreshSession() { + refreshSession(): void { this.oidcSecurityService .forceRefreshSession() .subscribe((result) => console.log(result)); } - logout() { + logout(): void { this.oidcSecurityService .logoff() .subscribe((result) => console.log(result)); } - logoffAndRevokeTokens() { + logoffAndRevokeTokens(): void { this.oidcSecurityService .logoffAndRevokeTokens() .subscribe((result) => console.log(result)); } - revokeRefreshToken() { + revokeRefreshToken(): void { this.oidcSecurityService .revokeRefreshToken() .subscribe((result) => console.log(result)); } - revokeAccessToken() { + revokeAccessToken(): void { this.oidcSecurityService .revokeAccessToken() .subscribe((result) => console.log(result)); diff --git a/projects/sample-code-flow-auth0/src/app/unauthorized/unauthorized.component.ts b/projects/sample-code-flow-auth0/src/app/unauthorized/unauthorized.component.ts index dbe965047..0ab5a6c46 100644 --- a/projects/sample-code-flow-auth0/src/app/unauthorized/unauthorized.component.ts +++ b/projects/sample-code-flow-auth0/src/app/unauthorized/unauthorized.component.ts @@ -1,11 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-unauthorized', templateUrl: 'unauthorized.component.html', }) -export class UnauthorizedComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class UnauthorizedComponent {} diff --git a/projects/sample-code-flow-auto-login-all-routes/src/app/customers/customers.component.ts b/projects/sample-code-flow-auto-login-all-routes/src/app/customers/customers.component.ts index 7833b920b..553e924d7 100644 --- a/projects/sample-code-flow-auto-login-all-routes/src/app/customers/customers.component.ts +++ b/projects/sample-code-flow-auto-login-all-routes/src/app/customers/customers.component.ts @@ -1,12 +1,8 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-customers', templateUrl: './customers.component.html', styleUrls: ['./customers.component.css'], }) -export class CustomersComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class CustomersComponent {} diff --git a/projects/sample-code-flow-auto-login-all-routes/src/app/home/home.component.ts b/projects/sample-code-flow-auto-login-all-routes/src/app/home/home.component.ts index 041acd881..44f8933bf 100644 --- a/projects/sample-code-flow-auto-login-all-routes/src/app/home/home.component.ts +++ b/projects/sample-code-flow-auto-login-all-routes/src/app/home/home.component.ts @@ -1,13 +1,12 @@ import { Component, OnInit } from '@angular/core'; -import { OidcSecurityService, UserDataResult } from 'angular-auth-oidc-client'; -import { Observable } from 'rxjs'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-home', templateUrl: 'home.component.html', }) export class HomeComponent implements OnInit { - userData$: Observable; + userData$ = this.oidcSecurityService.userData$; isAuthenticated = false; constructor(public oidcSecurityService: OidcSecurityService) {} @@ -20,6 +19,5 @@ export class HomeComponent implements OnInit { console.warn('authenticated: ', isAuthenticated); } ); - this.userData$ = this.oidcSecurityService.userData$; } } diff --git a/projects/sample-code-flow-auto-login-all-routes/src/app/navigation/navigation.component.ts b/projects/sample-code-flow-auto-login-all-routes/src/app/navigation/navigation.component.ts index b072893dd..cba9bcb84 100644 --- a/projects/sample-code-flow-auto-login-all-routes/src/app/navigation/navigation.component.ts +++ b/projects/sample-code-flow-auto-login-all-routes/src/app/navigation/navigation.component.ts @@ -7,7 +7,7 @@ import { OidcSecurityService } from 'angular-auth-oidc-client'; styleUrls: ['navigation.component.css'], }) export class NavigationComponent implements OnInit { - isAuthenticated: boolean; + isAuthenticated = false; constructor(public oidcSecurityService: OidcSecurityService) {} diff --git a/projects/sample-code-flow-auto-login-all-routes/src/app/protected/protected.component.ts b/projects/sample-code-flow-auto-login-all-routes/src/app/protected/protected.component.ts index 024769909..cf8dec94a 100644 --- a/projects/sample-code-flow-auto-login-all-routes/src/app/protected/protected.component.ts +++ b/projects/sample-code-flow-auto-login-all-routes/src/app/protected/protected.component.ts @@ -1,12 +1,8 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-protected', templateUrl: './protected.component.html', styleUrls: ['./protected.component.css'], }) -export class ProtectedComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class ProtectedComponent {} diff --git a/projects/sample-code-flow-auto-login-all-routes/src/app/unauthorized/unauthorized.component.ts b/projects/sample-code-flow-auto-login-all-routes/src/app/unauthorized/unauthorized.component.ts index 834791f20..0ab5a6c46 100644 --- a/projects/sample-code-flow-auto-login-all-routes/src/app/unauthorized/unauthorized.component.ts +++ b/projects/sample-code-flow-auto-login-all-routes/src/app/unauthorized/unauthorized.component.ts @@ -1,16 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-unauthorized', templateUrl: 'unauthorized.component.html', }) -export class UnauthorizedComponent implements OnInit { - public message: string; - public values: any[]; - - constructor() { - this.message = 'UnauthorizedComponent constructor'; - } - - ngOnInit() {} -} +export class UnauthorizedComponent {} diff --git a/projects/sample-code-flow-auto-login/src/app/app.component.spec.ts b/projects/sample-code-flow-auto-login/src/app/app.component.spec.ts index 148e4d442..3ab1a5a07 100644 --- a/projects/sample-code-flow-auto-login/src/app/app.component.spec.ts +++ b/projects/sample-code-flow-auto-login/src/app/app.component.spec.ts @@ -11,19 +11,23 @@ describe('AppComponent', () => { it('should create the app', () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); }); it(`should have as title 'sample-code-flow-auto-login'`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('sample-code-flow-auto-login'); }); it('should render title in a h1 tag', () => { const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain( 'Welcome to sample-code-flow-auto-login!' ); diff --git a/projects/sample-code-flow-auto-login/src/app/app.component.ts b/projects/sample-code-flow-auto-login/src/app/app.component.ts index bc6b4f475..c36e3f095 100644 --- a/projects/sample-code-flow-auto-login/src/app/app.component.ts +++ b/projects/sample-code-flow-auto-login/src/app/app.component.ts @@ -7,28 +7,28 @@ import { OidcSecurityService } from 'angular-auth-oidc-client'; styleUrls: ['./app.component.css'], }) export class AppComponent implements OnInit { - constructor(private oidcSecurityService: OidcSecurityService) {} + constructor(private readonly oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService .checkAuth() - .subscribe(({ isAuthenticated, userData, accessToken }) => { + .subscribe(({ isAuthenticated, accessToken }) => { console.log('app authenticated', isAuthenticated); console.log(`Current access token is '${accessToken}'`); }); } - login() { + login(): void { console.log('start login'); this.oidcSecurityService.authorize(); } - refreshSession() { + refreshSession(): void { console.log('start refreshSession'); this.oidcSecurityService.authorize(); } - logout() { + logout(): void { console.log('start logoff'); this.oidcSecurityService .logoff() diff --git a/projects/sample-code-flow-auto-login/src/app/customers/customers.component.ts b/projects/sample-code-flow-auto-login/src/app/customers/customers.component.ts index 18ca1ef1b..553e924d7 100644 --- a/projects/sample-code-flow-auto-login/src/app/customers/customers.component.ts +++ b/projects/sample-code-flow-auto-login/src/app/customers/customers.component.ts @@ -1,12 +1,8 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-customers', templateUrl: './customers.component.html', styleUrls: ['./customers.component.css'], }) -export class CustomersComponent implements OnInit { - constructor() {} - - ngOnInit(): void {} -} +export class CustomersComponent {} diff --git a/projects/sample-code-flow-auto-login/src/app/forbidden/forbidden.component.ts b/projects/sample-code-flow-auto-login/src/app/forbidden/forbidden.component.ts index f67a993a9..97de43383 100644 --- a/projects/sample-code-flow-auto-login/src/app/forbidden/forbidden.component.ts +++ b/projects/sample-code-flow-auto-login/src/app/forbidden/forbidden.component.ts @@ -8,9 +8,9 @@ import { OidcSecurityService } from 'angular-auth-oidc-client'; export class ForbiddenComponent implements OnInit { public isAuthenticated = false; - constructor(private oidcSecurityService: OidcSecurityService) {} + constructor(private readonly oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService.isAuthenticated$.subscribe( ({ isAuthenticated }) => { this.isAuthenticated = isAuthenticated; diff --git a/projects/sample-code-flow-auto-login/src/app/home/home.component.ts b/projects/sample-code-flow-auto-login/src/app/home/home.component.ts index 6b5d9cb0f..1dc68879c 100644 --- a/projects/sample-code-flow-auto-login/src/app/home/home.component.ts +++ b/projects/sample-code-flow-auto-login/src/app/home/home.component.ts @@ -1,18 +1,18 @@ import { Component, OnInit } from '@angular/core'; -import { OidcSecurityService, UserDataResult } from 'angular-auth-oidc-client'; -import { Observable } from 'rxjs'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-home', templateUrl: 'home.component.html', }) export class HomeComponent implements OnInit { - userData$: Observable; + userData$ = this.oidcSecurityService.userData$; + isAuthenticated = false; constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService.isAuthenticated$.subscribe( ({ isAuthenticated }) => { this.isAuthenticated = isAuthenticated; @@ -20,7 +20,5 @@ export class HomeComponent implements OnInit { console.warn('authenticated: ', isAuthenticated); } ); - - this.userData$ = this.oidcSecurityService.userData$; } } diff --git a/projects/sample-code-flow-auto-login/src/app/navigation/navigation.component.ts b/projects/sample-code-flow-auto-login/src/app/navigation/navigation.component.ts index b072893dd..09062d668 100644 --- a/projects/sample-code-flow-auto-login/src/app/navigation/navigation.component.ts +++ b/projects/sample-code-flow-auto-login/src/app/navigation/navigation.component.ts @@ -7,11 +7,11 @@ import { OidcSecurityService } from 'angular-auth-oidc-client'; styleUrls: ['navigation.component.css'], }) export class NavigationComponent implements OnInit { - isAuthenticated: boolean; + isAuthenticated = false; constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService.isAuthenticated$.subscribe( ({ isAuthenticated }) => { this.isAuthenticated = isAuthenticated; @@ -21,15 +21,15 @@ export class NavigationComponent implements OnInit { ); } - login() { + login(): void { this.oidcSecurityService.authorize(); } - refreshSession() { + refreshSession(): void { this.oidcSecurityService.authorize(); } - logout() { + logout(): void { this.oidcSecurityService .logoff() .subscribe((result) => console.log(result)); diff --git a/projects/sample-code-flow-auto-login/src/app/protected/protected.component.ts b/projects/sample-code-flow-auto-login/src/app/protected/protected.component.ts index 024769909..cf8dec94a 100644 --- a/projects/sample-code-flow-auto-login/src/app/protected/protected.component.ts +++ b/projects/sample-code-flow-auto-login/src/app/protected/protected.component.ts @@ -1,12 +1,8 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-protected', templateUrl: './protected.component.html', styleUrls: ['./protected.component.css'], }) -export class ProtectedComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class ProtectedComponent {} diff --git a/projects/sample-code-flow-auto-login/src/app/unauthorized/unauthorized.component.ts b/projects/sample-code-flow-auto-login/src/app/unauthorized/unauthorized.component.ts index 834791f20..0ab5a6c46 100644 --- a/projects/sample-code-flow-auto-login/src/app/unauthorized/unauthorized.component.ts +++ b/projects/sample-code-flow-auto-login/src/app/unauthorized/unauthorized.component.ts @@ -1,16 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-unauthorized', templateUrl: 'unauthorized.component.html', }) -export class UnauthorizedComponent implements OnInit { - public message: string; - public values: any[]; - - constructor() { - this.message = 'UnauthorizedComponent constructor'; - } - - ngOnInit() {} -} +export class UnauthorizedComponent {} diff --git a/projects/sample-code-flow-azure-b2c/src/app/forbidden/forbidden.component.ts b/projects/sample-code-flow-azure-b2c/src/app/forbidden/forbidden.component.ts index b5416954e..df59c5512 100644 --- a/projects/sample-code-flow-azure-b2c/src/app/forbidden/forbidden.component.ts +++ b/projects/sample-code-flow-azure-b2c/src/app/forbidden/forbidden.component.ts @@ -1,12 +1,8 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-forbidden', templateUrl: './forbidden.component.html', styleUrls: ['./forbidden.component.css'], }) -export class ForbiddenComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class ForbiddenComponent {} diff --git a/projects/sample-code-flow-azure-b2c/src/app/home/home.component.ts b/projects/sample-code-flow-azure-b2c/src/app/home/home.component.ts index 041acd881..1dc68879c 100644 --- a/projects/sample-code-flow-azure-b2c/src/app/home/home.component.ts +++ b/projects/sample-code-flow-azure-b2c/src/app/home/home.component.ts @@ -1,18 +1,18 @@ import { Component, OnInit } from '@angular/core'; -import { OidcSecurityService, UserDataResult } from 'angular-auth-oidc-client'; -import { Observable } from 'rxjs'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-home', templateUrl: 'home.component.html', }) export class HomeComponent implements OnInit { - userData$: Observable; + userData$ = this.oidcSecurityService.userData$; + isAuthenticated = false; constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService.isAuthenticated$.subscribe( ({ isAuthenticated }) => { this.isAuthenticated = isAuthenticated; @@ -20,6 +20,5 @@ export class HomeComponent implements OnInit { console.warn('authenticated: ', isAuthenticated); } ); - this.userData$ = this.oidcSecurityService.userData$; } } diff --git a/projects/sample-code-flow-azure-b2c/src/app/nav-menu/nav-menu.component.ts b/projects/sample-code-flow-azure-b2c/src/app/nav-menu/nav-menu.component.ts index c0486cbe8..8b660791c 100644 --- a/projects/sample-code-flow-azure-b2c/src/app/nav-menu/nav-menu.component.ts +++ b/projects/sample-code-flow-azure-b2c/src/app/nav-menu/nav-menu.component.ts @@ -8,11 +8,12 @@ import { OidcSecurityService } from 'angular-auth-oidc-client'; }) export class NavMenuComponent implements OnInit { isExpanded = false; - isAuthenticated: boolean; + + isAuthenticated = false; constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService.isAuthenticated$.subscribe( ({ isAuthenticated }) => { this.isAuthenticated = isAuthenticated; @@ -22,27 +23,27 @@ export class NavMenuComponent implements OnInit { ); } - login() { + login(): void { this.oidcSecurityService.authorize(); } - refreshSession() { + refreshSession(): void { this.oidcSecurityService .forceRefreshSession() .subscribe((result) => console.log(result)); } - logout() { + logout(): void { this.oidcSecurityService .logoff() .subscribe((result) => console.log(result)); } - collapse() { + collapse(): void { this.isExpanded = false; } - toggle() { + toggle(): void { this.isExpanded = !this.isExpanded; } } diff --git a/projects/sample-code-flow-azure-b2c/src/app/protected/protected.component.ts b/projects/sample-code-flow-azure-b2c/src/app/protected/protected.component.ts index 024769909..cf8dec94a 100644 --- a/projects/sample-code-flow-azure-b2c/src/app/protected/protected.component.ts +++ b/projects/sample-code-flow-azure-b2c/src/app/protected/protected.component.ts @@ -1,12 +1,8 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-protected', templateUrl: './protected.component.html', styleUrls: ['./protected.component.css'], }) -export class ProtectedComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class ProtectedComponent {} diff --git a/projects/sample-code-flow-azure-b2c/src/app/unauthorized/unauthorized.component.ts b/projects/sample-code-flow-azure-b2c/src/app/unauthorized/unauthorized.component.ts index fe06a6912..c5c1482b9 100644 --- a/projects/sample-code-flow-azure-b2c/src/app/unauthorized/unauthorized.component.ts +++ b/projects/sample-code-flow-azure-b2c/src/app/unauthorized/unauthorized.component.ts @@ -1,12 +1,8 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-unauthorized', templateUrl: './unauthorized.component.html', styleUrls: ['./unauthorized.component.css'], }) -export class UnauthorizedComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class UnauthorizedComponent {} diff --git a/projects/sample-code-flow-azuread/src/app/app.component.ts b/projects/sample-code-flow-azuread/src/app/app.component.ts index a46fd01f4..f145dffc8 100644 --- a/projects/sample-code-flow-azuread/src/app/app.component.ts +++ b/projects/sample-code-flow-azuread/src/app/app.component.ts @@ -1,28 +1,24 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-root', templateUrl: 'app.component.html', }) -export class AppComponent implements OnInit, OnDestroy { +export class AppComponent { constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() {} - - ngOnDestroy(): void {} - - login() { + login(): void { console.log('start login'); this.oidcSecurityService.authorize(); } - refreshSession() { + refreshSession(): void { console.log('start refreshSession'); this.oidcSecurityService.authorize(); } - logout() { + logout(): void { console.log('start logoff'); this.oidcSecurityService .logoff() diff --git a/projects/sample-code-flow-azuread/src/app/forbidden/forbidden.component.ts b/projects/sample-code-flow-azuread/src/app/forbidden/forbidden.component.ts index b5416954e..df59c5512 100644 --- a/projects/sample-code-flow-azuread/src/app/forbidden/forbidden.component.ts +++ b/projects/sample-code-flow-azuread/src/app/forbidden/forbidden.component.ts @@ -1,12 +1,8 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-forbidden', templateUrl: './forbidden.component.html', styleUrls: ['./forbidden.component.css'], }) -export class ForbiddenComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class ForbiddenComponent {} diff --git a/projects/sample-code-flow-azuread/src/app/home/home.component.ts b/projects/sample-code-flow-azuread/src/app/home/home.component.ts index 041acd881..1dc68879c 100644 --- a/projects/sample-code-flow-azuread/src/app/home/home.component.ts +++ b/projects/sample-code-flow-azuread/src/app/home/home.component.ts @@ -1,18 +1,18 @@ import { Component, OnInit } from '@angular/core'; -import { OidcSecurityService, UserDataResult } from 'angular-auth-oidc-client'; -import { Observable } from 'rxjs'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-home', templateUrl: 'home.component.html', }) export class HomeComponent implements OnInit { - userData$: Observable; + userData$ = this.oidcSecurityService.userData$; + isAuthenticated = false; constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService.isAuthenticated$.subscribe( ({ isAuthenticated }) => { this.isAuthenticated = isAuthenticated; @@ -20,6 +20,5 @@ export class HomeComponent implements OnInit { console.warn('authenticated: ', isAuthenticated); } ); - this.userData$ = this.oidcSecurityService.userData$; } } diff --git a/projects/sample-code-flow-azuread/src/app/nav-menu/nav-menu.component.ts b/projects/sample-code-flow-azuread/src/app/nav-menu/nav-menu.component.ts index e1b120bca..8b660791c 100644 --- a/projects/sample-code-flow-azuread/src/app/nav-menu/nav-menu.component.ts +++ b/projects/sample-code-flow-azuread/src/app/nav-menu/nav-menu.component.ts @@ -9,11 +9,11 @@ import { OidcSecurityService } from 'angular-auth-oidc-client'; export class NavMenuComponent implements OnInit { isExpanded = false; - isAuthenticated: boolean; + isAuthenticated = false; constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService.isAuthenticated$.subscribe( ({ isAuthenticated }) => { this.isAuthenticated = isAuthenticated; @@ -23,26 +23,27 @@ export class NavMenuComponent implements OnInit { ); } - login() { + login(): void { this.oidcSecurityService.authorize(); } - refreshSession() { + refreshSession(): void { this.oidcSecurityService .forceRefreshSession() .subscribe((result) => console.log(result)); } - logout() { + logout(): void { this.oidcSecurityService .logoff() .subscribe((result) => console.log(result)); } - collapse() { + + collapse(): void { this.isExpanded = false; } - toggle() { + toggle(): void { this.isExpanded = !this.isExpanded; } } diff --git a/projects/sample-code-flow-azuread/src/app/protected/protected.component.ts b/projects/sample-code-flow-azuread/src/app/protected/protected.component.ts index 024769909..cf8dec94a 100644 --- a/projects/sample-code-flow-azuread/src/app/protected/protected.component.ts +++ b/projects/sample-code-flow-azuread/src/app/protected/protected.component.ts @@ -1,12 +1,8 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-protected', templateUrl: './protected.component.html', styleUrls: ['./protected.component.css'], }) -export class ProtectedComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class ProtectedComponent {} diff --git a/projects/sample-code-flow-azuread/src/app/unauthorized/unauthorized.component.ts b/projects/sample-code-flow-azuread/src/app/unauthorized/unauthorized.component.ts index fe06a6912..c5c1482b9 100644 --- a/projects/sample-code-flow-azuread/src/app/unauthorized/unauthorized.component.ts +++ b/projects/sample-code-flow-azuread/src/app/unauthorized/unauthorized.component.ts @@ -1,12 +1,8 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-unauthorized', templateUrl: './unauthorized.component.html', styleUrls: ['./unauthorized.component.css'], }) -export class UnauthorizedComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class UnauthorizedComponent {} diff --git a/projects/sample-code-flow-http-config/src/app/app.component.spec.ts b/projects/sample-code-flow-http-config/src/app/app.component.spec.ts index ca37aa2b0..7627c677e 100644 --- a/projects/sample-code-flow-http-config/src/app/app.component.spec.ts +++ b/projects/sample-code-flow-http-config/src/app/app.component.spec.ts @@ -11,19 +11,23 @@ describe('AppComponent', () => { it('should create the app', () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); }); it(`should have as title 'testSts'`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('testSts'); }); it('should render title in a h1 tag', () => { const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain( 'Welcome to testSts!' ); diff --git a/projects/sample-code-flow-http-config/src/app/app.component.ts b/projects/sample-code-flow-http-config/src/app/app.component.ts index 2af316f38..37035e710 100644 --- a/projects/sample-code-flow-http-config/src/app/app.component.ts +++ b/projects/sample-code-flow-http-config/src/app/app.component.ts @@ -13,18 +13,16 @@ import { filter } from 'rxjs/operators'; export class AppComponent implements OnInit { constructor( public oidcSecurityService: OidcSecurityService, - private eventService: PublicEventsService + private readonly eventService: PublicEventsService ) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService .checkAuth() - .subscribe( - ({ isAuthenticated, userData, accessToken, idToken, configId }) => { - console.log('app authenticated', isAuthenticated); - console.log(`Current access token is '${accessToken}'`); - } - ); + .subscribe(({ isAuthenticated, accessToken }) => { + console.log('app authenticated', isAuthenticated); + console.log(`Current access token is '${accessToken}'`); + }); this.eventService .registerForEvents() diff --git a/projects/sample-code-flow-http-config/src/app/auth-config.module.ts b/projects/sample-code-flow-http-config/src/app/auth-config.module.ts index a0562f6ec..1924cd5f9 100644 --- a/projects/sample-code-flow-http-config/src/app/auth-config.module.ts +++ b/projects/sample-code-flow-http-config/src/app/auth-config.module.ts @@ -1,4 +1,3 @@ -/* eslint-disable arrow-body-style */ import { HttpClient } from '@angular/common/http'; import { NgModule } from '@angular/core'; import { @@ -9,7 +8,7 @@ import { } from 'angular-auth-oidc-client'; import { map } from 'rxjs/operators'; -export const httpLoaderFactory = (httpClient: HttpClient) => { +export const httpLoaderFactory = (httpClient: HttpClient): StsConfigLoader => { const config$ = httpClient .get( `https://offeringsolutions-sts.azurewebsites.net/api/ClientAppSettings` diff --git a/projects/sample-code-flow-http-config/src/app/home/home.component.html b/projects/sample-code-flow-http-config/src/app/home/home.component.html index 9699438c4..05257e97e 100644 --- a/projects/sample-code-flow-http-config/src/app/home/home.component.html +++ b/projects/sample-code-flow-http-config/src/app/home/home.component.html @@ -17,7 +17,7 @@
userData
{{ userData$ | async | json }}
- {{ checkSessionChanged }} + {{ checkSessionChanged$ | async }}
diff --git a/projects/sample-code-flow-http-config/src/app/home/home.component.ts b/projects/sample-code-flow-http-config/src/app/home/home.component.ts index e2d9e753c..68897361e 100644 --- a/projects/sample-code-flow-http-config/src/app/home/home.component.ts +++ b/projects/sample-code-flow-http-config/src/app/home/home.component.ts @@ -1,31 +1,22 @@ import { Component, OnInit } from '@angular/core'; -import { - OidcClientNotification, - OidcSecurityService, - OpenIdConfiguration, - UserDataResult, -} from 'angular-auth-oidc-client'; -import { Observable } from 'rxjs'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-home', templateUrl: 'home.component.html', }) export class HomeComponent implements OnInit { - configuration$: Observable; - userDataChanged$: Observable>; - userData$: Observable; + configuration$ = this.oidcSecurityService.getConfiguration(); + + userData$ = this.oidcSecurityService.userData$; + isAuthenticated = false; - checkSessionChanged$: Observable; - checkSessionChanged: any; - constructor(public oidcSecurityService: OidcSecurityService) {} + checkSessionChanged$ = this.oidcSecurityService.checkSessionChanged$; - ngOnInit() { - this.configuration$ = this.oidcSecurityService.getConfiguration(); - this.userData$ = this.oidcSecurityService.userData$; - this.checkSessionChanged$ = this.oidcSecurityService.checkSessionChanged$; + constructor(public oidcSecurityService: OidcSecurityService) {} + ngOnInit(): void { this.oidcSecurityService.isAuthenticated$.subscribe( ({ isAuthenticated }) => { this.isAuthenticated = isAuthenticated; @@ -35,23 +26,23 @@ export class HomeComponent implements OnInit { ); } - login() { + login(): void { this.oidcSecurityService.authorize(); } - refreshSession() { + refreshSession(): void { this.oidcSecurityService .forceRefreshSession() .subscribe((result) => console.log(result)); } - logout() { + logout(): void { this.oidcSecurityService .logoff() .subscribe((result) => console.log(result)); } - logoffLocal() { + logoffLocal(): void { this.oidcSecurityService.logoffLocal(); } } diff --git a/projects/sample-code-flow-http-config/src/app/unauthorized/unauthorized.component.ts b/projects/sample-code-flow-http-config/src/app/unauthorized/unauthorized.component.ts index dbe965047..0ab5a6c46 100644 --- a/projects/sample-code-flow-http-config/src/app/unauthorized/unauthorized.component.ts +++ b/projects/sample-code-flow-http-config/src/app/unauthorized/unauthorized.component.ts @@ -1,11 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-unauthorized', templateUrl: 'unauthorized.component.html', }) -export class UnauthorizedComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class UnauthorizedComponent {} diff --git a/projects/sample-code-flow-lazy-loaded/src/app/app.component.spec.ts b/projects/sample-code-flow-lazy-loaded/src/app/app.component.spec.ts index cb1791c81..fd2aef139 100644 --- a/projects/sample-code-flow-lazy-loaded/src/app/app.component.spec.ts +++ b/projects/sample-code-flow-lazy-loaded/src/app/app.component.spec.ts @@ -13,19 +13,23 @@ describe('AppComponent', () => { it('should create the app', () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.componentInstance; + expect(app).toBeTruthy(); }); it(`should have as title 'sample-code-flow-lazy-loaded'`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.componentInstance; + expect(app.title).toEqual('sample-code-flow-lazy-loaded'); }); it('should render title', () => { const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); const compiled = fixture.nativeElement; + expect(compiled.querySelector('.content span').textContent).toContain( 'sample-code-flow-lazy-loaded app is running!' ); diff --git a/projects/sample-code-flow-lazy-loaded/src/app/app.component.ts b/projects/sample-code-flow-lazy-loaded/src/app/app.component.ts index c07232124..5a673e109 100644 --- a/projects/sample-code-flow-lazy-loaded/src/app/app.component.ts +++ b/projects/sample-code-flow-lazy-loaded/src/app/app.component.ts @@ -12,7 +12,7 @@ export class AppComponent { constructor(public oidcSecurityService: OidcSecurityService) { this.oidcSecurityService .checkAuth() - .subscribe(({ isAuthenticated, userData, accessToken }) => { + .subscribe(({ isAuthenticated, accessToken }) => { console.log('app authenticated', isAuthenticated); console.log(`Current access token is '${accessToken}'`); }); diff --git a/projects/sample-code-flow-lazy-loaded/src/app/lazy/lazy.component.ts b/projects/sample-code-flow-lazy-loaded/src/app/lazy/lazy.component.ts index 521558649..fa488f9cc 100644 --- a/projects/sample-code-flow-lazy-loaded/src/app/lazy/lazy.component.ts +++ b/projects/sample-code-flow-lazy-loaded/src/app/lazy/lazy.component.ts @@ -8,6 +8,7 @@ import { OidcSecurityService } from 'angular-auth-oidc-client'; }) export class LazyComponent implements OnInit { isAuthenticated = false; + constructor(public oidcSecurityService: OidcSecurityService) {} ngOnInit(): void { @@ -20,11 +21,11 @@ export class LazyComponent implements OnInit { ); } - login() { + login(): void { this.oidcSecurityService.authorize(); } - logout() { + logout(): void { this.oidcSecurityService .logoff() .subscribe((result) => console.log(result)); diff --git a/projects/sample-code-flow-lazy-loaded/src/app/lazy/lazy.module.ts b/projects/sample-code-flow-lazy-loaded/src/app/lazy/lazy.module.ts index e6b8a70dc..36e12980c 100644 --- a/projects/sample-code-flow-lazy-loaded/src/app/lazy/lazy.module.ts +++ b/projects/sample-code-flow-lazy-loaded/src/app/lazy/lazy.module.ts @@ -7,6 +7,4 @@ import { LazyComponent } from './lazy.component'; declarations: [LazyComponent], imports: [CommonModule, LazyRoutingModule], }) -export class LazyModule { - constructor() {} -} +export class LazyModule {} diff --git a/projects/sample-code-flow-multi-AAD/src/app/app.component.spec.ts b/projects/sample-code-flow-multi-AAD/src/app/app.component.spec.ts index ca37aa2b0..7627c677e 100644 --- a/projects/sample-code-flow-multi-AAD/src/app/app.component.spec.ts +++ b/projects/sample-code-flow-multi-AAD/src/app/app.component.spec.ts @@ -11,19 +11,23 @@ describe('AppComponent', () => { it('should create the app', () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); }); it(`should have as title 'testSts'`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('testSts'); }); it('should render title in a h1 tag', () => { const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain( 'Welcome to testSts!' ); diff --git a/projects/sample-code-flow-multi-AAD/src/app/app.component.ts b/projects/sample-code-flow-multi-AAD/src/app/app.component.ts index e0491ddd3..57612a8ef 100644 --- a/projects/sample-code-flow-multi-AAD/src/app/app.component.ts +++ b/projects/sample-code-flow-multi-AAD/src/app/app.component.ts @@ -8,7 +8,7 @@ import { OidcSecurityService } from 'angular-auth-oidc-client'; export class AppComponent implements OnInit { constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService .checkAuthMultiple() .subscribe(([{ isAuthenticated, userData, accessToken }]) => { diff --git a/projects/sample-code-flow-multi-AAD/src/app/home/home.component.ts b/projects/sample-code-flow-multi-AAD/src/app/home/home.component.ts index 587af52cd..c979d65f9 100644 --- a/projects/sample-code-flow-multi-AAD/src/app/home/home.component.ts +++ b/projects/sample-code-flow-multi-AAD/src/app/home/home.component.ts @@ -1,53 +1,38 @@ -import { Component, OnInit } from '@angular/core'; -import { - AuthenticatedResult, - OidcClientNotification, - OidcSecurityService, - OpenIdConfiguration, - UserDataResult, -} from 'angular-auth-oidc-client'; -import { Observable } from 'rxjs'; +import { Component } from '@angular/core'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-home', templateUrl: 'home.component.html', }) -export class HomeComponent implements OnInit { - configurations: OpenIdConfiguration[]; +export class HomeComponent { + configurations = this.oidcSecurityService.getConfigurations(); - userDataChanged$: Observable>; + userData$ = this.oidcSecurityService.userData$; - userData$: Observable; - - isAuthenticated$: Observable; + isAuthenticated$ = this.oidcSecurityService.isAuthenticated$; constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { - this.configurations = this.oidcSecurityService.getConfigurations(); - this.userData$ = this.oidcSecurityService.userData$; - this.isAuthenticated$ = this.oidcSecurityService.isAuthenticated$; - } - - login(configId: string) { + login(configId: string | undefined): void { this.oidcSecurityService.authorize(configId); } - forceRefreshSession() { + forceRefreshSession(): void { this.oidcSecurityService .forceRefreshSession() .subscribe((result) => console.warn(result)); } - logout(configId: string) { + logout(configId: string | undefined): void { this.oidcSecurityService .logoff(configId) .subscribe((result) => console.log(result)); } - refreshSession(configId: string) { + refreshSession(configId: string | undefined): void { this.oidcSecurityService - .forceRefreshSession(null, configId) + .forceRefreshSession(undefined, configId) .subscribe((result) => console.log(result)); } } diff --git a/projects/sample-code-flow-multi-AAD/src/app/unauthorized/unauthorized.component.ts b/projects/sample-code-flow-multi-AAD/src/app/unauthorized/unauthorized.component.ts index dbe965047..0ab5a6c46 100644 --- a/projects/sample-code-flow-multi-AAD/src/app/unauthorized/unauthorized.component.ts +++ b/projects/sample-code-flow-multi-AAD/src/app/unauthorized/unauthorized.component.ts @@ -1,11 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-unauthorized', templateUrl: 'unauthorized.component.html', }) -export class UnauthorizedComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class UnauthorizedComponent {} diff --git a/projects/sample-code-flow-multi-Auth0-ID4-popup/src/app/app.component.spec.ts b/projects/sample-code-flow-multi-Auth0-ID4-popup/src/app/app.component.spec.ts index ca37aa2b0..7627c677e 100644 --- a/projects/sample-code-flow-multi-Auth0-ID4-popup/src/app/app.component.spec.ts +++ b/projects/sample-code-flow-multi-Auth0-ID4-popup/src/app/app.component.spec.ts @@ -11,19 +11,23 @@ describe('AppComponent', () => { it('should create the app', () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); }); it(`should have as title 'testSts'`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('testSts'); }); it('should render title in a h1 tag', () => { const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain( 'Welcome to testSts!' ); diff --git a/projects/sample-code-flow-multi-Auth0-ID4-popup/src/app/app.component.ts b/projects/sample-code-flow-multi-Auth0-ID4-popup/src/app/app.component.ts index e0491ddd3..57612a8ef 100644 --- a/projects/sample-code-flow-multi-Auth0-ID4-popup/src/app/app.component.ts +++ b/projects/sample-code-flow-multi-Auth0-ID4-popup/src/app/app.component.ts @@ -8,7 +8,7 @@ import { OidcSecurityService } from 'angular-auth-oidc-client'; export class AppComponent implements OnInit { constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService .checkAuthMultiple() .subscribe(([{ isAuthenticated, userData, accessToken }]) => { diff --git a/projects/sample-code-flow-multi-Auth0-ID4-popup/src/app/home/home.component.ts b/projects/sample-code-flow-multi-Auth0-ID4-popup/src/app/home/home.component.ts index ba96ae4ff..8a50ed339 100644 --- a/projects/sample-code-flow-multi-Auth0-ID4-popup/src/app/home/home.component.ts +++ b/projects/sample-code-flow-multi-Auth0-ID4-popup/src/app/home/home.component.ts @@ -1,41 +1,26 @@ -import { Component, OnInit } from '@angular/core'; -import { - AuthenticatedResult, - OidcClientNotification, - OidcSecurityService, - OpenIdConfiguration, - UserDataResult, -} from 'angular-auth-oidc-client'; -import { Observable } from 'rxjs'; +import { Component } from '@angular/core'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-home', templateUrl: 'home.component.html', }) -export class HomeComponent implements OnInit { - configurations: OpenIdConfiguration[]; +export class HomeComponent { + configurations = this.oidcSecurityService.getConfigurations(); - userDataChanged$: Observable>; + userData$ = this.oidcSecurityService.userData$; - userData$: Observable; - - isAuthenticated$: Observable; + isAuthenticated$ = this.oidcSecurityService.isAuthenticated$; constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { - this.configurations = this.oidcSecurityService.getConfigurations(); - this.userData$ = this.oidcSecurityService.userData$; - this.isAuthenticated$ = this.oidcSecurityService.isAuthenticated$; - } - - login(configId: string) { + login(configId: string): void { this.oidcSecurityService.authorize(configId); } - loginWithPopup(configId: string) { + loginWithPopup(configId: string | undefined): void { this.oidcSecurityService - .authorizeWithPopUp(null, null, configId) + .authorizeWithPopUp(undefined, undefined, configId) .subscribe(({ isAuthenticated, userData, accessToken, errorMessage }) => { console.log(isAuthenticated); console.log(userData); @@ -44,29 +29,29 @@ export class HomeComponent implements OnInit { }); } - openWindow() { + openWindow(): void { window.open('/', '_blank'); } - forceRefreshSession() { + forceRefreshSession(): void { this.oidcSecurityService .forceRefreshSession() .subscribe((result) => console.warn(result)); } - logout(configId: string) { + logout(configId: string | undefined): void { this.oidcSecurityService .logoff(configId) .subscribe((result) => console.log(result)); } - refreshSessionId4(configId: string) { + refreshSessionId4(configId: string | undefined): void { this.oidcSecurityService - .forceRefreshSession(null, configId) + .forceRefreshSession(undefined, configId) .subscribe((result) => console.log(result)); } - refreshSessionAuth0(configId: string) { + refreshSessionAuth0(configId: string | undefined): void { this.oidcSecurityService .forceRefreshSession( { scope: 'openid profile offline_access auth0-user-api-spa' }, @@ -75,13 +60,13 @@ export class HomeComponent implements OnInit { .subscribe((result) => console.log(result)); } - logoffAndRevokeTokens(configId: string) { + logoffAndRevokeTokens(configId: string | undefined): void { this.oidcSecurityService .logoffAndRevokeTokens(configId) .subscribe((result) => console.log(result)); } - revokeRefreshToken(configId: string) { + revokeRefreshToken(configId: string | undefined): void { this.oidcSecurityService .revokeRefreshToken(null, configId) .subscribe((result) => console.log(result)); diff --git a/projects/sample-code-flow-multi-Auth0-ID4-popup/src/app/unauthorized/unauthorized.component.ts b/projects/sample-code-flow-multi-Auth0-ID4-popup/src/app/unauthorized/unauthorized.component.ts index dbe965047..0ab5a6c46 100644 --- a/projects/sample-code-flow-multi-Auth0-ID4-popup/src/app/unauthorized/unauthorized.component.ts +++ b/projects/sample-code-flow-multi-Auth0-ID4-popup/src/app/unauthorized/unauthorized.component.ts @@ -1,11 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-unauthorized', templateUrl: 'unauthorized.component.html', }) -export class UnauthorizedComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class UnauthorizedComponent {} diff --git a/projects/sample-code-flow-multi-Auth0-ID4/src/app/app.component.spec.ts b/projects/sample-code-flow-multi-Auth0-ID4/src/app/app.component.spec.ts index ca37aa2b0..7627c677e 100644 --- a/projects/sample-code-flow-multi-Auth0-ID4/src/app/app.component.spec.ts +++ b/projects/sample-code-flow-multi-Auth0-ID4/src/app/app.component.spec.ts @@ -11,19 +11,23 @@ describe('AppComponent', () => { it('should create the app', () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); }); it(`should have as title 'testSts'`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('testSts'); }); it('should render title in a h1 tag', () => { const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain( 'Welcome to testSts!' ); diff --git a/projects/sample-code-flow-multi-Auth0-ID4/src/app/app.component.ts b/projects/sample-code-flow-multi-Auth0-ID4/src/app/app.component.ts index 033879303..57612a8ef 100644 --- a/projects/sample-code-flow-multi-Auth0-ID4/src/app/app.component.ts +++ b/projects/sample-code-flow-multi-Auth0-ID4/src/app/app.component.ts @@ -8,8 +8,7 @@ import { OidcSecurityService } from 'angular-auth-oidc-client'; export class AppComponent implements OnInit { constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { - //this.oidcSecurityService.preloadAuthWellKnownDocument().subscribe(); + ngOnInit(): void { this.oidcSecurityService .checkAuthMultiple() .subscribe(([{ isAuthenticated, userData, accessToken }]) => { diff --git a/projects/sample-code-flow-multi-Auth0-ID4/src/app/home/home.component.ts b/projects/sample-code-flow-multi-Auth0-ID4/src/app/home/home.component.ts index 317638a83..c065b5d26 100644 --- a/projects/sample-code-flow-multi-Auth0-ID4/src/app/home/home.component.ts +++ b/projects/sample-code-flow-multi-Auth0-ID4/src/app/home/home.component.ts @@ -1,57 +1,42 @@ -import { Component, OnInit } from '@angular/core'; -import { - AuthenticatedResult, - OidcClientNotification, - OidcSecurityService, - OpenIdConfiguration, - UserDataResult, -} from 'angular-auth-oidc-client'; -import { Observable } from 'rxjs'; +import { Component } from '@angular/core'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-home', templateUrl: 'home.component.html', }) -export class HomeComponent implements OnInit { - configurations: OpenIdConfiguration[]; +export class HomeComponent { + configurations = this.oidcSecurityService.getConfigurations(); - userDataChanged$: Observable>; + userData$ = this.oidcSecurityService.userData$; - userData$: Observable; - - isAuthenticated$: Observable; + isAuthenticated$ = this.oidcSecurityService.isAuthenticated$; constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { - this.configurations = this.oidcSecurityService.getConfigurations(); - this.userData$ = this.oidcSecurityService.userData$; - this.isAuthenticated$ = this.oidcSecurityService.isAuthenticated$; - } - - login(configId: string) { + login(configId: string | undefined): void { this.oidcSecurityService.authorize(configId); } - forceRefreshSession() { + forceRefreshSession(): void { this.oidcSecurityService .forceRefreshSession() .subscribe((result) => console.warn(result)); } - logout(configId: string) { + logout(configId: string | undefined): void { this.oidcSecurityService .logoff(configId) .subscribe((result) => console.log(result)); } - refreshSessionId4(configId: string) { + refreshSessionId4(configId: string | undefined): void { this.oidcSecurityService - .forceRefreshSession(null, configId) + .forceRefreshSession(undefined, configId) .subscribe((result) => console.log(result)); } - refreshSessionAuth0(configId: string) { + refreshSessionAuth0(configId: string | undefined): void { this.oidcSecurityService .forceRefreshSession( { scope: 'openid profile offline_access auth0-user-api-spa' }, @@ -60,13 +45,13 @@ export class HomeComponent implements OnInit { .subscribe((result) => console.log(result)); } - logoffAndRevokeTokens(configId: string) { + logoffAndRevokeTokens(configId: string | undefined): void { this.oidcSecurityService .logoffAndRevokeTokens(configId) .subscribe((result) => console.log(result)); } - revokeRefreshToken(configId: string) { + revokeRefreshToken(configId: string | undefined): void { this.oidcSecurityService .revokeRefreshToken(null, configId) .subscribe((result) => console.log(result)); diff --git a/projects/sample-code-flow-multi-Auth0-ID4/src/app/unauthorized/unauthorized.component.ts b/projects/sample-code-flow-multi-Auth0-ID4/src/app/unauthorized/unauthorized.component.ts index dbe965047..0ab5a6c46 100644 --- a/projects/sample-code-flow-multi-Auth0-ID4/src/app/unauthorized/unauthorized.component.ts +++ b/projects/sample-code-flow-multi-Auth0-ID4/src/app/unauthorized/unauthorized.component.ts @@ -1,11 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-unauthorized', templateUrl: 'unauthorized.component.html', }) -export class UnauthorizedComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class UnauthorizedComponent {} diff --git a/projects/sample-code-flow-multi-Azure-B2C/src/app/app.component.spec.ts b/projects/sample-code-flow-multi-Azure-B2C/src/app/app.component.spec.ts index ca37aa2b0..7627c677e 100644 --- a/projects/sample-code-flow-multi-Azure-B2C/src/app/app.component.spec.ts +++ b/projects/sample-code-flow-multi-Azure-B2C/src/app/app.component.spec.ts @@ -11,19 +11,23 @@ describe('AppComponent', () => { it('should create the app', () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); }); it(`should have as title 'testSts'`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('testSts'); }); it('should render title in a h1 tag', () => { const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain( 'Welcome to testSts!' ); diff --git a/projects/sample-code-flow-multi-Azure-B2C/src/app/app.component.ts b/projects/sample-code-flow-multi-Azure-B2C/src/app/app.component.ts index e0491ddd3..57612a8ef 100644 --- a/projects/sample-code-flow-multi-Azure-B2C/src/app/app.component.ts +++ b/projects/sample-code-flow-multi-Azure-B2C/src/app/app.component.ts @@ -8,7 +8,7 @@ import { OidcSecurityService } from 'angular-auth-oidc-client'; export class AppComponent implements OnInit { constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService .checkAuthMultiple() .subscribe(([{ isAuthenticated, userData, accessToken }]) => { diff --git a/projects/sample-code-flow-multi-Azure-B2C/src/app/home/home.component.ts b/projects/sample-code-flow-multi-Azure-B2C/src/app/home/home.component.ts index 6e36843a3..8c77cf290 100644 --- a/projects/sample-code-flow-multi-Azure-B2C/src/app/home/home.component.ts +++ b/projects/sample-code-flow-multi-Azure-B2C/src/app/home/home.component.ts @@ -1,48 +1,36 @@ -import { Component, OnInit } from '@angular/core'; -import { - AuthenticatedResult, - OidcClientNotification, - OidcSecurityService, - OpenIdConfiguration, - UserDataResult, -} from 'angular-auth-oidc-client'; -import { Observable } from 'rxjs'; +import { Component } from '@angular/core'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-home', templateUrl: 'home.component.html', }) -export class HomeComponent implements OnInit { - configurations: OpenIdConfiguration[]; - userDataChanged$: Observable>; - userData$: Observable; - isAuthenticated$: Observable; +export class HomeComponent { + configurations = this.oidcSecurityService.getConfigurations(); - constructor(public oidcSecurityService: OidcSecurityService) {} + userData$ = this.oidcSecurityService.userData$; - ngOnInit() { - this.configurations = this.oidcSecurityService.getConfigurations(); - this.userData$ = this.oidcSecurityService.userData$; - this.isAuthenticated$ = this.oidcSecurityService.isAuthenticated$; - } + isAuthenticated$ = this.oidcSecurityService.isAuthenticated$; + + constructor(public oidcSecurityService: OidcSecurityService) {} - login(configId: string) { + login(configId: string | undefined): void { this.oidcSecurityService.authorize(configId); } - forceRefreshSession() { + forceRefreshSession(): void { this.oidcSecurityService .forceRefreshSession() .subscribe((result) => console.warn(result)); } - logout(configId: string) { + logout(configId: string | undefined): void { this.oidcSecurityService.logoff(configId); } - refreshSession(configId: string) { + refreshSession(configId: string | undefined): void { this.oidcSecurityService - .forceRefreshSession(null, configId) + .forceRefreshSession(undefined, configId) .subscribe((result) => console.log(result)); } } diff --git a/projects/sample-code-flow-multi-Azure-B2C/src/app/unauthorized/unauthorized.component.ts b/projects/sample-code-flow-multi-Azure-B2C/src/app/unauthorized/unauthorized.component.ts index dbe965047..0ab5a6c46 100644 --- a/projects/sample-code-flow-multi-Azure-B2C/src/app/unauthorized/unauthorized.component.ts +++ b/projects/sample-code-flow-multi-Azure-B2C/src/app/unauthorized/unauthorized.component.ts @@ -1,11 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-unauthorized', templateUrl: 'unauthorized.component.html', }) -export class UnauthorizedComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class UnauthorizedComponent {} diff --git a/projects/sample-code-flow-multi-iframe/src/app/app.component.spec.ts b/projects/sample-code-flow-multi-iframe/src/app/app.component.spec.ts index ca37aa2b0..7627c677e 100644 --- a/projects/sample-code-flow-multi-iframe/src/app/app.component.spec.ts +++ b/projects/sample-code-flow-multi-iframe/src/app/app.component.spec.ts @@ -11,19 +11,23 @@ describe('AppComponent', () => { it('should create the app', () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); }); it(`should have as title 'testSts'`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('testSts'); }); it('should render title in a h1 tag', () => { const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain( 'Welcome to testSts!' ); diff --git a/projects/sample-code-flow-multi-iframe/src/app/app.component.ts b/projects/sample-code-flow-multi-iframe/src/app/app.component.ts index e0491ddd3..57612a8ef 100644 --- a/projects/sample-code-flow-multi-iframe/src/app/app.component.ts +++ b/projects/sample-code-flow-multi-iframe/src/app/app.component.ts @@ -8,7 +8,7 @@ import { OidcSecurityService } from 'angular-auth-oidc-client'; export class AppComponent implements OnInit { constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService .checkAuthMultiple() .subscribe(([{ isAuthenticated, userData, accessToken }]) => { diff --git a/projects/sample-code-flow-multi-iframe/src/app/home/home.component.ts b/projects/sample-code-flow-multi-iframe/src/app/home/home.component.ts index 1df2c2634..04b8e972a 100644 --- a/projects/sample-code-flow-multi-iframe/src/app/home/home.component.ts +++ b/projects/sample-code-flow-multi-iframe/src/app/home/home.component.ts @@ -1,50 +1,30 @@ -import { Component, OnInit } from '@angular/core'; -import { - AuthenticatedResult, - OidcClientNotification, - OidcSecurityService, - OpenIdConfiguration, - UserDataResult, -} from 'angular-auth-oidc-client'; -import { Observable } from 'rxjs'; +import { Component } from '@angular/core'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-home', templateUrl: 'home.component.html', }) -export class HomeComponent implements OnInit { - configurations: OpenIdConfiguration[]; - userDataChanged$: Observable>; - userData$: Observable; - isAuthenticated$: Observable; +export class HomeComponent { + configurations = this.oidcSecurityService.getConfigurations(); - constructor(public oidcSecurityService: OidcSecurityService) {} + userData$ = this.oidcSecurityService.userData$; - ngOnInit() { - this.configurations = this.oidcSecurityService.getConfigurations(); - this.userData$ = this.oidcSecurityService.userData$; - this.isAuthenticated$ = this.oidcSecurityService.isAuthenticated$; - } + isAuthenticated$ = this.oidcSecurityService.isAuthenticated$; + + constructor(public oidcSecurityService: OidcSecurityService) {} - login(configId: string) { + login(configId: string | undefined): void { this.oidcSecurityService.authorize(configId); } - forceRefreshSession() { + forceRefreshSession(): void { this.oidcSecurityService .forceRefreshSession() .subscribe((result) => console.warn(result)); } - logout(configId: string) { + logout(configId: string | undefined): void { this.oidcSecurityService.logoff(configId); } - - // login(configId: string) { - // this.oidcSecurityService.authorize(configId); - // } - - // logout(configId: string) { - // this.oidcSecurityService.logoff(configId); - // } } diff --git a/projects/sample-code-flow-multi-iframe/src/app/unauthorized/unauthorized.component.ts b/projects/sample-code-flow-multi-iframe/src/app/unauthorized/unauthorized.component.ts index dbe965047..0ab5a6c46 100644 --- a/projects/sample-code-flow-multi-iframe/src/app/unauthorized/unauthorized.component.ts +++ b/projects/sample-code-flow-multi-iframe/src/app/unauthorized/unauthorized.component.ts @@ -1,11 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-unauthorized', templateUrl: 'unauthorized.component.html', }) -export class UnauthorizedComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class UnauthorizedComponent {} diff --git a/projects/sample-code-flow-multi-iframe/tsconfig.app.json b/projects/sample-code-flow-multi-iframe/tsconfig.app.json index c3c483759..82b3d1b3a 100644 --- a/projects/sample-code-flow-multi-iframe/tsconfig.app.json +++ b/projects/sample-code-flow-multi-iframe/tsconfig.app.json @@ -6,5 +6,5 @@ "types": [] }, "files": ["src/main.ts", "src/polyfills.ts"], - "include": ["src/**/*.d.ts"] + "exclude": ["**/*.spec.ts"] } diff --git a/projects/sample-code-flow-par/src/app/home/home.component.ts b/projects/sample-code-flow-par/src/app/home/home.component.ts index 9f57ad25e..3beced079 100644 --- a/projects/sample-code-flow-par/src/app/home/home.component.ts +++ b/projects/sample-code-flow-par/src/app/home/home.component.ts @@ -1,27 +1,18 @@ import { Component, OnInit } from '@angular/core'; -import { - OidcClientNotification, - OidcSecurityService, - OpenIdConfiguration, - UserDataResult, -} from 'angular-auth-oidc-client'; -import { Observable } from 'rxjs'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-home', templateUrl: 'home.component.html', }) export class HomeComponent implements OnInit { - configuration$: Observable; - userDataChanged$: Observable>; - userData$: Observable; + configuration$ = this.oidcSecurityService.getConfiguration(); + userData$ = this.oidcSecurityService.userData$; isAuthenticated = false; + constructor(public oidcSecurityService: OidcSecurityService) {} ngOnInit() { - this.configuration$ = this.oidcSecurityService.getConfiguration(); - this.userData$ = this.oidcSecurityService.userData$; - this.oidcSecurityService.isAuthenticated$.subscribe( ({ isAuthenticated }) => { this.isAuthenticated = isAuthenticated; diff --git a/projects/sample-code-flow-par/src/app/unauthorized/unauthorized.component.ts b/projects/sample-code-flow-par/src/app/unauthorized/unauthorized.component.ts index dbe965047..0ab5a6c46 100644 --- a/projects/sample-code-flow-par/src/app/unauthorized/unauthorized.component.ts +++ b/projects/sample-code-flow-par/src/app/unauthorized/unauthorized.component.ts @@ -1,11 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-unauthorized', templateUrl: 'unauthorized.component.html', }) -export class UnauthorizedComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class UnauthorizedComponent {} diff --git a/projects/sample-code-flow-popup/src/app/app.component.ts b/projects/sample-code-flow-popup/src/app/app.component.ts index bdeb01aec..e1f60be22 100644 --- a/projects/sample-code-flow-popup/src/app/app.component.ts +++ b/projects/sample-code-flow-popup/src/app/app.component.ts @@ -1,10 +1,5 @@ import { Component } from '@angular/core'; -import { - OidcSecurityService, - OpenIdConfiguration, - UserDataResult, -} from 'angular-auth-oidc-client'; -import { Observable } from 'rxjs'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-root', @@ -12,20 +7,15 @@ import { Observable } from 'rxjs'; styleUrls: ['./app.component.css'], }) export class AppComponent { - title = 'sample-code-flow-popup'; + userData$ = this.oidcSecurityService.userData$; - userData$: Observable; - - configuration$: Observable; + configuration$ = this.oidcSecurityService.getConfiguration(); isAuthenticated = false; constructor(public oidcSecurityService: OidcSecurityService) {} ngOnInit() { - this.configuration$ = this.oidcSecurityService.getConfiguration(); - this.userData$ = this.oidcSecurityService.userData$; - this.oidcSecurityService.isAuthenticated$.subscribe( ({ isAuthenticated }) => { this.isAuthenticated = isAuthenticated; diff --git a/projects/sample-code-flow-refresh-tokens/src/app/app.component.spec.ts b/projects/sample-code-flow-refresh-tokens/src/app/app.component.spec.ts index ca37aa2b0..7627c677e 100644 --- a/projects/sample-code-flow-refresh-tokens/src/app/app.component.spec.ts +++ b/projects/sample-code-flow-refresh-tokens/src/app/app.component.spec.ts @@ -11,19 +11,23 @@ describe('AppComponent', () => { it('should create the app', () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); }); it(`should have as title 'testSts'`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('testSts'); }); it('should render title in a h1 tag', () => { const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain( 'Welcome to testSts!' ); diff --git a/projects/sample-code-flow-refresh-tokens/src/app/app.component.ts b/projects/sample-code-flow-refresh-tokens/src/app/app.component.ts index aeed09d33..6ce193529 100644 --- a/projects/sample-code-flow-refresh-tokens/src/app/app.component.ts +++ b/projects/sample-code-flow-refresh-tokens/src/app/app.component.ts @@ -8,10 +8,10 @@ import { OidcSecurityService } from 'angular-auth-oidc-client'; export class AppComponent implements OnInit { constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService .checkAuth() - .subscribe(({ isAuthenticated, userData, accessToken }) => { + .subscribe(({ isAuthenticated, accessToken }) => { console.log('app authenticated', isAuthenticated); console.log(`Current access token is '${accessToken}'`); }); diff --git a/projects/sample-code-flow-refresh-tokens/src/app/home/home.component.ts b/projects/sample-code-flow-refresh-tokens/src/app/home/home.component.ts index e56e9c29d..55499d3c9 100644 --- a/projects/sample-code-flow-refresh-tokens/src/app/home/home.component.ts +++ b/projects/sample-code-flow-refresh-tokens/src/app/home/home.component.ts @@ -1,27 +1,20 @@ import { Component, OnInit } from '@angular/core'; -import { - OidcClientNotification, - OidcSecurityService, - OpenIdConfiguration, - UserDataResult, -} from 'angular-auth-oidc-client'; -import { Observable } from 'rxjs'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-home', templateUrl: 'home.component.html', }) export class HomeComponent implements OnInit { - configuration$: Observable; - userDataChanged$: Observable>; - userData$: Observable; + configuration$ = this.oidcSecurityService.getConfiguration(); + + userData$ = this.oidcSecurityService.userData$; + isAuthenticated = false; - constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { - this.configuration$ = this.oidcSecurityService.getConfiguration(); - this.userData$ = this.oidcSecurityService.userData$; + constructor(public oidcSecurityService: OidcSecurityService) {} + ngOnInit(): void { this.oidcSecurityService.isAuthenticated$.subscribe( ({ isAuthenticated }) => { this.isAuthenticated = isAuthenticated; @@ -31,35 +24,35 @@ export class HomeComponent implements OnInit { ); } - login() { + login(): void { this.oidcSecurityService.authorize(); } - refreshSession() { + refreshSession(): void { this.oidcSecurityService .forceRefreshSession() .subscribe((result) => console.log(result)); } - logout() { + logout(): void { this.oidcSecurityService .logoff() .subscribe((result) => console.log(result)); } - logoffAndRevokeTokens() { + logoffAndRevokeTokens(): void { this.oidcSecurityService .logoffAndRevokeTokens() .subscribe((result) => console.log(result)); } - revokeRefreshToken() { + revokeRefreshToken(): void { this.oidcSecurityService .revokeRefreshToken() .subscribe((result) => console.log(result)); } - revokeAccessToken() { + revokeAccessToken(): void { this.oidcSecurityService .revokeAccessToken() .subscribe((result) => console.log(result)); diff --git a/projects/sample-code-flow-refresh-tokens/src/app/unauthorized/unauthorized.component.ts b/projects/sample-code-flow-refresh-tokens/src/app/unauthorized/unauthorized.component.ts index dbe965047..0ab5a6c46 100644 --- a/projects/sample-code-flow-refresh-tokens/src/app/unauthorized/unauthorized.component.ts +++ b/projects/sample-code-flow-refresh-tokens/src/app/unauthorized/unauthorized.component.ts @@ -1,11 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-unauthorized', templateUrl: 'unauthorized.component.html', }) -export class UnauthorizedComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class UnauthorizedComponent {} diff --git a/projects/sample-code-flow-standalone/src/app/app.component.spec.ts b/projects/sample-code-flow-standalone/src/app/app.component.spec.ts index 6731cff5f..5635392c6 100644 --- a/projects/sample-code-flow-standalone/src/app/app.component.spec.ts +++ b/projects/sample-code-flow-standalone/src/app/app.component.spec.ts @@ -11,19 +11,23 @@ describe('AppComponent', () => { it('should create the app', () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); }); it(`should have as title 'sample-code-flow-standalone'`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('sample-code-flow-standalone'); }); it('should render title in a h1 tag', () => { const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain( 'Welcome to sample-code-flow-standalone!' ); diff --git a/projects/sample-code-flow-standalone/src/app/app.component.ts b/projects/sample-code-flow-standalone/src/app/app.component.ts index 2427505fc..b89f41da5 100644 --- a/projects/sample-code-flow-standalone/src/app/app.component.ts +++ b/projects/sample-code-flow-standalone/src/app/app.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit } from '@angular/core'; -import { OidcSecurityService } from 'angular-auth-oidc-client'; import { RouterOutlet } from '@angular/router'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; import { NavigationComponent } from './navigation/navigation.component'; @Component({ @@ -11,28 +11,28 @@ import { NavigationComponent } from './navigation/navigation.component'; imports: [RouterOutlet, NavigationComponent], }) export class AppComponent implements OnInit { - constructor(private oidcSecurityService: OidcSecurityService) {} + constructor(private readonly oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService .checkAuth() - .subscribe(({ isAuthenticated, userData, accessToken }) => { + .subscribe(({ isAuthenticated, accessToken }) => { console.log('app authenticated', isAuthenticated); console.log(`Current access token is '${accessToken}'`); }); } - login() { + login(): void { console.log('start login'); this.oidcSecurityService.authorize(); } - refreshSession() { + refreshSession(): void { console.log('start refreshSession'); this.oidcSecurityService.authorize(); } - logout() { + logout(): void { console.log('start logoff'); this.oidcSecurityService .logoff() diff --git a/projects/sample-code-flow-standalone/src/app/customers/customers.component.ts b/projects/sample-code-flow-standalone/src/app/customers/customers.component.ts index 582b9ec01..e0b5217e2 100644 --- a/projects/sample-code-flow-standalone/src/app/customers/customers.component.ts +++ b/projects/sample-code-flow-standalone/src/app/customers/customers.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-customers', @@ -6,8 +6,4 @@ import { Component, OnInit } from '@angular/core'; styleUrls: ['./customers.component.css'], standalone: true, }) -export class CustomersComponent implements OnInit { - constructor() {} - - ngOnInit(): void {} -} +export class CustomersComponent {} diff --git a/projects/sample-code-flow-standalone/src/app/forbidden/forbidden.component.ts b/projects/sample-code-flow-standalone/src/app/forbidden/forbidden.component.ts index 066e7e63d..6433011e5 100644 --- a/projects/sample-code-flow-standalone/src/app/forbidden/forbidden.component.ts +++ b/projects/sample-code-flow-standalone/src/app/forbidden/forbidden.component.ts @@ -9,9 +9,9 @@ import { OidcSecurityService } from 'angular-auth-oidc-client'; export class ForbiddenComponent implements OnInit { public isAuthenticated = false; - constructor(private oidcSecurityService: OidcSecurityService) {} + constructor(private readonly oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService.isAuthenticated$.subscribe( ({ isAuthenticated }) => { this.isAuthenticated = isAuthenticated; diff --git a/projects/sample-code-flow-standalone/src/app/home/home.component.ts b/projects/sample-code-flow-standalone/src/app/home/home.component.ts index 3778641aa..e5543f690 100644 --- a/projects/sample-code-flow-standalone/src/app/home/home.component.ts +++ b/projects/sample-code-flow-standalone/src/app/home/home.component.ts @@ -1,7 +1,6 @@ -import { Component, OnInit } from '@angular/core'; -import { OidcSecurityService, UserDataResult } from 'angular-auth-oidc-client'; -import { Observable } from 'rxjs'; import { AsyncPipe, JsonPipe } from '@angular/common'; +import { Component, OnInit } from '@angular/core'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-home', @@ -10,12 +9,13 @@ import { AsyncPipe, JsonPipe } from '@angular/common'; imports: [AsyncPipe, JsonPipe], }) export class HomeComponent implements OnInit { - userData$: Observable; + userData$ = this.oidcSecurityService.userData$; + isAuthenticated = false; constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService.isAuthenticated$.subscribe( ({ isAuthenticated }) => { this.isAuthenticated = isAuthenticated; @@ -23,7 +23,5 @@ export class HomeComponent implements OnInit { console.warn('authenticated: ', isAuthenticated); } ); - - this.userData$ = this.oidcSecurityService.userData$; } } diff --git a/projects/sample-code-flow-standalone/src/app/navigation/navigation.component.ts b/projects/sample-code-flow-standalone/src/app/navigation/navigation.component.ts index 87400fc2e..ce8811b87 100644 --- a/projects/sample-code-flow-standalone/src/app/navigation/navigation.component.ts +++ b/projects/sample-code-flow-standalone/src/app/navigation/navigation.component.ts @@ -1,7 +1,7 @@ +import { NgIf } from '@angular/common'; import { Component, OnInit } from '@angular/core'; -import { OidcSecurityService } from 'angular-auth-oidc-client'; import { RouterLink } from '@angular/router'; -import { NgIf } from '@angular/common'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-navigation', @@ -11,11 +11,11 @@ import { NgIf } from '@angular/common'; imports: [RouterLink, NgIf], }) export class NavigationComponent implements OnInit { - isAuthenticated: boolean; + isAuthenticated = false; constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService.isAuthenticated$.subscribe( ({ isAuthenticated }) => { this.isAuthenticated = isAuthenticated; @@ -25,15 +25,15 @@ export class NavigationComponent implements OnInit { ); } - login() { + login(): void { this.oidcSecurityService.authorize(); } - refreshSession() { + refreshSession(): void { this.oidcSecurityService.authorize(); } - logout() { + logout(): void { this.oidcSecurityService .logoff() .subscribe((result) => console.log(result)); diff --git a/projects/sample-code-flow-standalone/src/app/protected/protected.component.ts b/projects/sample-code-flow-standalone/src/app/protected/protected.component.ts index 4accef624..720e0ca07 100644 --- a/projects/sample-code-flow-standalone/src/app/protected/protected.component.ts +++ b/projects/sample-code-flow-standalone/src/app/protected/protected.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-protected', @@ -6,8 +6,4 @@ import { Component, OnInit } from '@angular/core'; styleUrls: ['./protected.component.css'], standalone: true, }) -export class ProtectedComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class ProtectedComponent {} diff --git a/projects/sample-code-flow-standalone/src/app/unauthorized/unauthorized.component.ts b/projects/sample-code-flow-standalone/src/app/unauthorized/unauthorized.component.ts index 66c0ab6c0..c1bdf9548 100644 --- a/projects/sample-code-flow-standalone/src/app/unauthorized/unauthorized.component.ts +++ b/projects/sample-code-flow-standalone/src/app/unauthorized/unauthorized.component.ts @@ -1,17 +1,8 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-unauthorized', templateUrl: 'unauthorized.component.html', standalone: true, }) -export class UnauthorizedComponent implements OnInit { - public message: string; - public values: any[]; - - constructor() { - this.message = 'UnauthorizedComponent constructor'; - } - - ngOnInit() {} -} +export class UnauthorizedComponent {} diff --git a/projects/sample-implicit-flow-google/src/app/app.component.spec.ts b/projects/sample-implicit-flow-google/src/app/app.component.spec.ts index d8e18bd90..5fd32df13 100644 --- a/projects/sample-implicit-flow-google/src/app/app.component.spec.ts +++ b/projects/sample-implicit-flow-google/src/app/app.component.spec.ts @@ -13,19 +13,23 @@ describe('AppComponent', () => { it('should create the app', () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.componentInstance; + expect(app).toBeTruthy(); }); it(`should have as title 'sample-implicit-flow-google'`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.componentInstance; + expect(app.title).toEqual('sample-implicit-flow-google'); }); it('should render title', () => { const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); const compiled = fixture.nativeElement; + expect(compiled.querySelector('.content span').textContent).toContain( 'sample-implicit-flow-google app is running!' ); diff --git a/projects/sample-implicit-flow-google/src/app/app.component.ts b/projects/sample-implicit-flow-google/src/app/app.component.ts index 4384a02a9..f98a1bf6a 100644 --- a/projects/sample-implicit-flow-google/src/app/app.component.ts +++ b/projects/sample-implicit-flow-google/src/app/app.component.ts @@ -1,4 +1,4 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { OidcSecurityService } from 'angular-auth-oidc-client'; @@ -6,13 +6,13 @@ import { OidcSecurityService } from 'angular-auth-oidc-client'; selector: 'app-root', templateUrl: 'app.component.html', }) -export class AppComponent implements OnInit, OnDestroy { +export class AppComponent implements OnInit { constructor( public oidcSecurityService: OidcSecurityService, - private router: Router + private readonly router: Router ) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService .checkAuth() @@ -29,26 +29,24 @@ export class AppComponent implements OnInit, OnDestroy { }); } - ngOnDestroy(): void {} - - login() { + login(): void { console.log('start login'); this.oidcSecurityService.authorize(); } - refreshSession() { + refreshSession(): void { console.log('start refreshSession'); this.oidcSecurityService.authorize(); } - logout() { + logout(): void { console.log('start logoff'); this.oidcSecurityService .logoff() .subscribe((result) => console.log(result)); } - private navigateToStoredEndpoint() { + private navigateToStoredEndpoint(): void { const path = this.read('redirect'); if (this.router.url === path) { @@ -64,6 +62,7 @@ export class AppComponent implements OnInit, OnDestroy { private read(key: string): any { const data = localStorage.getItem(key); + if (data != null) { return JSON.parse(data); } diff --git a/projects/sample-implicit-flow-google/src/app/auto-login/auto-login.component.ts b/projects/sample-implicit-flow-google/src/app/auto-login/auto-login.component.ts index d63c1bfb5..397c4d632 100644 --- a/projects/sample-implicit-flow-google/src/app/auto-login/auto-login.component.ts +++ b/projects/sample-implicit-flow-google/src/app/auto-login/auto-login.component.ts @@ -6,11 +6,9 @@ import { OidcSecurityService } from 'angular-auth-oidc-client'; templateUrl: './auto-login.component.html', }) export class AutoLoginComponent implements OnInit { - lang: any; - constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService .checkAuth() .subscribe(() => this.oidcSecurityService.authorize()); diff --git a/projects/sample-implicit-flow-google/src/app/forbidden/forbidden.component.ts b/projects/sample-implicit-flow-google/src/app/forbidden/forbidden.component.ts index 7431c8b3a..1d58d56da 100644 --- a/projects/sample-implicit-flow-google/src/app/forbidden/forbidden.component.ts +++ b/projects/sample-implicit-flow-google/src/app/forbidden/forbidden.component.ts @@ -1,16 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-forbidden', templateUrl: 'forbidden.component.html', }) -export class ForbiddenComponent implements OnInit { - public message: string; - public values: any[]; - - constructor() { - this.message = 'ForbiddenComponent constructor'; - } - - ngOnInit() {} -} +export class ForbiddenComponent {} diff --git a/projects/sample-implicit-flow-google/src/app/home/home.component.ts b/projects/sample-implicit-flow-google/src/app/home/home.component.ts index 041acd881..1dc68879c 100644 --- a/projects/sample-implicit-flow-google/src/app/home/home.component.ts +++ b/projects/sample-implicit-flow-google/src/app/home/home.component.ts @@ -1,18 +1,18 @@ import { Component, OnInit } from '@angular/core'; -import { OidcSecurityService, UserDataResult } from 'angular-auth-oidc-client'; -import { Observable } from 'rxjs'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-home', templateUrl: 'home.component.html', }) export class HomeComponent implements OnInit { - userData$: Observable; + userData$ = this.oidcSecurityService.userData$; + isAuthenticated = false; constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService.isAuthenticated$.subscribe( ({ isAuthenticated }) => { this.isAuthenticated = isAuthenticated; @@ -20,6 +20,5 @@ export class HomeComponent implements OnInit { console.warn('authenticated: ', isAuthenticated); } ); - this.userData$ = this.oidcSecurityService.userData$; } } diff --git a/projects/sample-implicit-flow-google/src/app/navigation/navigation.component.ts b/projects/sample-implicit-flow-google/src/app/navigation/navigation.component.ts index 5dd55eca7..65ceb8f62 100644 --- a/projects/sample-implicit-flow-google/src/app/navigation/navigation.component.ts +++ b/projects/sample-implicit-flow-google/src/app/navigation/navigation.component.ts @@ -10,7 +10,7 @@ export class NavigationComponent implements OnInit { constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService.isAuthenticated$.subscribe( ({ isAuthenticated }) => { this.isAuthenticated = isAuthenticated; @@ -20,15 +20,15 @@ export class NavigationComponent implements OnInit { ); } - login() { + login(): void { this.oidcSecurityService.authorize(); } - refreshSession() { + refreshSession(): void { this.oidcSecurityService.authorize(); } - logout() { + logout(): void { this.oidcSecurityService .logoff() .subscribe((result) => console.log(result)); diff --git a/projects/sample-implicit-flow-google/src/app/unauthorized/unauthorized.component.ts b/projects/sample-implicit-flow-google/src/app/unauthorized/unauthorized.component.ts index 834791f20..0ab5a6c46 100644 --- a/projects/sample-implicit-flow-google/src/app/unauthorized/unauthorized.component.ts +++ b/projects/sample-implicit-flow-google/src/app/unauthorized/unauthorized.component.ts @@ -1,16 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-unauthorized', templateUrl: 'unauthorized.component.html', }) -export class UnauthorizedComponent implements OnInit { - public message: string; - public values: any[]; - - constructor() { - this.message = 'UnauthorizedComponent constructor'; - } - - ngOnInit() {} -} +export class UnauthorizedComponent {} diff --git a/projects/sample-implicit-flow-silent-renew/src/app/app.component.spec.ts b/projects/sample-implicit-flow-silent-renew/src/app/app.component.spec.ts index ca37aa2b0..7627c677e 100644 --- a/projects/sample-implicit-flow-silent-renew/src/app/app.component.spec.ts +++ b/projects/sample-implicit-flow-silent-renew/src/app/app.component.spec.ts @@ -11,19 +11,23 @@ describe('AppComponent', () => { it('should create the app', () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); }); it(`should have as title 'testSts'`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('testSts'); }); it('should render title in a h1 tag', () => { const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain( 'Welcome to testSts!' ); diff --git a/projects/sample-implicit-flow-silent-renew/src/app/app.component.ts b/projects/sample-implicit-flow-silent-renew/src/app/app.component.ts index 263e84250..0dc5f04c8 100644 --- a/projects/sample-implicit-flow-silent-renew/src/app/app.component.ts +++ b/projects/sample-implicit-flow-silent-renew/src/app/app.component.ts @@ -8,7 +8,7 @@ import { OidcSecurityService } from 'angular-auth-oidc-client'; export class AppComponent implements OnInit { constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { + ngOnInit(): void { this.oidcSecurityService .checkAuthIncludingServer() .subscribe((isAuthenticated) => diff --git a/projects/sample-implicit-flow-silent-renew/src/app/home/home.component.html b/projects/sample-implicit-flow-silent-renew/src/app/home/home.component.html index 98d4bf836..fccd2ae42 100644 --- a/projects/sample-implicit-flow-silent-renew/src/app/home/home.component.html +++ b/projects/sample-implicit-flow-silent-renew/src/app/home/home.component.html @@ -16,7 +16,7 @@
userData
{{ userData$ | async | json }}
- {{ checkSessionChanged }} + {{ checkSessionChanged$ | async }}
diff --git a/projects/sample-implicit-flow-silent-renew/src/app/home/home.component.ts b/projects/sample-implicit-flow-silent-renew/src/app/home/home.component.ts index 3a19f0432..915333fbf 100644 --- a/projects/sample-implicit-flow-silent-renew/src/app/home/home.component.ts +++ b/projects/sample-implicit-flow-silent-renew/src/app/home/home.component.ts @@ -1,30 +1,22 @@ import { Component, OnInit } from '@angular/core'; -import { - OidcClientNotification, - OidcSecurityService, - OpenIdConfiguration, - UserDataResult, -} from 'angular-auth-oidc-client'; -import { Observable } from 'rxjs'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; @Component({ selector: 'app-home', templateUrl: 'home.component.html', }) export class HomeComponent implements OnInit { - configuration$: Observable; - userDataChanged$: Observable>; - userData$: Observable; + configuration$ = this.oidcSecurityService.getConfiguration(); + + userData$ = this.oidcSecurityService.userData$; + isAuthenticated = false; - checkSessionChanged$: Observable; - checkSessionChanged: any; + + checkSessionChanged$ = this.oidcSecurityService.checkSessionChanged$; constructor(public oidcSecurityService: OidcSecurityService) {} - ngOnInit() { - this.configuration$ = this.oidcSecurityService.getConfiguration(); - this.userData$ = this.oidcSecurityService.userData$; - this.checkSessionChanged$ = this.oidcSecurityService.checkSessionChanged$; + ngOnInit(): void { this.oidcSecurityService.isAuthenticated$.subscribe( ({ isAuthenticated }) => { this.isAuthenticated = isAuthenticated; @@ -33,23 +25,24 @@ export class HomeComponent implements OnInit { } ); } - login() { + + login(): void { console.log('start login'); this.oidcSecurityService.authorize(); } - refreshSessionCheckSession() { + refreshSessionCheckSession(): void { console.log('start refreshSession'); this.oidcSecurityService.authorize(); } - forceRefreshSession() { + forceRefreshSession(): void { this.oidcSecurityService .forceRefreshSession() .subscribe((result) => console.log(result)); } - logout() { + logout(): void { console.log('start logoff'); this.oidcSecurityService .logoff() diff --git a/projects/sample-implicit-flow-silent-renew/src/app/unauthorized/unauthorized.component.ts b/projects/sample-implicit-flow-silent-renew/src/app/unauthorized/unauthorized.component.ts index dbe965047..0ab5a6c46 100644 --- a/projects/sample-implicit-flow-silent-renew/src/app/unauthorized/unauthorized.component.ts +++ b/projects/sample-implicit-flow-silent-renew/src/app/unauthorized/unauthorized.component.ts @@ -1,11 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-unauthorized', templateUrl: 'unauthorized.component.html', }) -export class UnauthorizedComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} +export class UnauthorizedComponent {} diff --git a/tsconfig.json b/tsconfig.json index cbdad7cf8..3605c04ed 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,7 @@ "baseUrl": "./", "outDir": "./dist/out-tsc", "forceConsistentCasingInFileNames": true, - "strict": false, + "strict": true, "paths": { "angular-auth-oidc-client": [ "dist/angular-auth-oidc-client/angular-auth-oidc-client",