From 5540c11ef8c3e00115c2dc09367eaf2356ca7326 Mon Sep 17 00:00:00 2001 From: chvostek Date: Mon, 2 Jun 2025 12:06:09 +0200 Subject: [PATCH 1/5] [NAE-2118] Implement OpenID Connector Auth for Admin node - create login-sso.component - add login sso button in login-form.component - update schema.ts with sso configuration --- nae.json | 6 +- .../src/assets/i18n/de.json | 1 + .../src/assets/i18n/en.json | 1 + .../src/assets/i18n/sk.json | 1 + .../src/commons/schema.ts | 7 ++ .../login/abstract-login-form.component.ts | 7 +- .../abstract-login-sso.component.spec.ts | 1 + .../login-sso/abstract-login-sso.component.ts | 113 ++++++++++++++++++ .../src/lib/forms/public-api.ts | 1 + .../lib/forms/login/login-form.component.html | 3 + .../lib/forms/login/login-form.component.ts | 6 +- .../src/lib/forms/login/login-form.module.ts | 5 +- .../login/login-sso/login-sso.component.html | 9 ++ .../login/login-sso/login-sso.component.scss | 0 .../login-sso/login-sso.component.spec.ts | 27 +++++ .../login/login-sso/login-sso.component.ts | 22 ++++ .../src/lib/forms/public-api.ts | 1 + 17 files changed, 204 insertions(+), 7 deletions(-) create mode 100644 projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.spec.ts create mode 100644 projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.ts create mode 100644 projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.html create mode 100644 projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.scss create mode 100644 projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.spec.ts create mode 100644 projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.ts diff --git a/nae.json b/nae.json index 2e5b56c538..b28e3ecb71 100644 --- a/nae.json +++ b/nae.json @@ -19,7 +19,11 @@ "sessionBearer": "X-Auth-Token", "sessionTimeoutEnabled": false, "sessionTimeout": 900, - "jwtBearer": "X-Jwt-Token" + "jwtBearer": "X-Jwt-Token", + "sso": { + "enable": true, + "redirectUrl": "https://netgrif.com" + } }, "resources": [ { diff --git a/projects/netgrif-components-core/src/assets/i18n/de.json b/projects/netgrif-components-core/src/assets/i18n/de.json index a8f7aa7ba6..4df093efa7 100644 --- a/projects/netgrif-components-core/src/assets/i18n/de.json +++ b/projects/netgrif-components-core/src/assets/i18n/de.json @@ -311,6 +311,7 @@ "login": "Benutzername", "wrongCredentials": "Falsche Anmeldeinformationen!", "loginButton": "Anmelden", + "ssoButton": "SSO-Anmeldung", "reset": "Kennwort wiederherstellen", "sign": "Registrieren", "enterPass": "Ihre Kennwort eingeben" diff --git a/projects/netgrif-components-core/src/assets/i18n/en.json b/projects/netgrif-components-core/src/assets/i18n/en.json index d2bbf05e8d..3a24d3e87c 100644 --- a/projects/netgrif-components-core/src/assets/i18n/en.json +++ b/projects/netgrif-components-core/src/assets/i18n/en.json @@ -311,6 +311,7 @@ "login": "Username", "wrongCredentials": "Wrong credentials!", "loginButton": "Log in", + "ssoButton": "Log with SSO", "reset": "Reset password", "sign": "Sign Up", "enterPass": "Enter your password" diff --git a/projects/netgrif-components-core/src/assets/i18n/sk.json b/projects/netgrif-components-core/src/assets/i18n/sk.json index e47da7ff94..15d2ca7c60 100644 --- a/projects/netgrif-components-core/src/assets/i18n/sk.json +++ b/projects/netgrif-components-core/src/assets/i18n/sk.json @@ -311,6 +311,7 @@ "login": "Prihlasovacie meno", "wrongCredentials": "Nesprávne prihlasovacie údaje!", "loginButton": "Prihlásiť", + "ssoButton": "Prihlásiť sa pomocou SSO", "reset": "Obnova hesla", "sign": "Registrovať", "enterPass": "Zadajte svoje heslo" diff --git a/projects/netgrif-components-core/src/commons/schema.ts b/projects/netgrif-components-core/src/commons/schema.ts index ae68c47ac8..15b3939c39 100644 --- a/projects/netgrif-components-core/src/commons/schema.ts +++ b/projects/netgrif-components-core/src/commons/schema.ts @@ -46,10 +46,17 @@ export interface Auth { authentication: string; sessionBearer?: string; endpoints?: string | { [k: string]: string }; + sso?: Sso; [k: string]: any; } +export interface Sso { + enable: boolean; + redirectUrl: string; + scopes: Array; +} + export interface Resource { name: string; address: string; diff --git a/projects/netgrif-components-core/src/lib/forms/login/abstract-login-form.component.ts b/projects/netgrif-components-core/src/lib/forms/login/abstract-login-form.component.ts index 448fe9516b..37579c2813 100644 --- a/projects/netgrif-components-core/src/lib/forms/login/abstract-login-form.component.ts +++ b/projects/netgrif-components-core/src/lib/forms/login/abstract-login-form.component.ts @@ -5,6 +5,8 @@ import {UserService} from '../../user/services/user.service'; import {User} from '../../user/models/user'; import {LoadingEmitter} from '../../utility/loading-emitter'; import {take} from 'rxjs/operators'; +import {ConfigurationService} from "../../configuration/configuration.service"; +import {Sso} from "../../../commons/schema"; @Component({ selector: 'ncc-abstract-login-field', @@ -15,6 +17,7 @@ export abstract class AbstractLoginFormComponent implements HasForm, OnDestroy { public rootFormGroup: FormGroup; public hidePassword = true; public loading: LoadingEmitter; + protected showSsoButton: boolean; @Input() public showSignUpButton: boolean; @Input() public showForgottenPasswordButton: boolean; @@ -23,7 +26,7 @@ export abstract class AbstractLoginFormComponent implements HasForm, OnDestroy { @Output() public signUp: EventEmitter; @Output() public formSubmit: EventEmitter; - protected constructor(formBuilder: FormBuilder, protected _userService: UserService) { + protected constructor(formBuilder: FormBuilder, protected _userService: UserService, protected _config: ConfigurationService) { this.rootFormGroup = formBuilder.group({ login: [''], password: [''] @@ -33,6 +36,8 @@ export abstract class AbstractLoginFormComponent implements HasForm, OnDestroy { this.signUp = new EventEmitter(); this.formSubmit = new EventEmitter(); this.loading = new LoadingEmitter(); + let ssoConfig: Sso = this._config.getConfigurationSubtree(['providers', 'auth', 'sso']) + this.showSsoButton = ssoConfig?.enable } ngOnDestroy(): void { diff --git a/projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.spec.ts b/projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.spec.ts new file mode 100644 index 0000000000..e73bf2b761 --- /dev/null +++ b/projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.spec.ts @@ -0,0 +1 @@ +// todo 2118 diff --git a/projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.ts b/projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.ts new file mode 100644 index 0000000000..a9c8d59095 --- /dev/null +++ b/projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.ts @@ -0,0 +1,113 @@ +import {Component, OnDestroy} from "@angular/core"; +import {ActivatedRoute, Params, Router} from "@angular/router"; +import {Observable, of, throwError} from "rxjs"; +import {catchError} from "rxjs/operators"; +import {HttpClient, HttpErrorResponse} from "@angular/common/http"; +import {ConfigurationService} from "../../../configuration/configuration.service"; +import {LoggerService} from '../../../logger/services/logger.service'; +import {LoadingEmitter} from '../../../utility/loading-emitter'; +import {SnackBarService} from "../../../snack-bar/services/snack-bar.service"; +import {Sso} from "../../../../commons/schema"; + + +@Component({ + selector: 'ncc-abstract-login-field', + template: '' +}) +export abstract class AbstractLoginSsoComponent implements OnDestroy { + + private _ssoConfig: Sso; + protected loading: LoadingEmitter; + + protected constructor( + protected _config: ConfigurationService, + protected _http: HttpClient, + protected _snackbar: SnackBarService, + protected _log: LoggerService, + protected _router: Router, + protected _activeRouter: ActivatedRoute, + ) { + this._ssoConfig = this._config.getConfigurationSubtree(['providers', 'auth', 'sso']); + this.loading = new LoadingEmitter(); + this._activeRouter.queryParams.subscribe((params) => { + if (!!params.code) { + this.loginFromCode(params); + } + }); + } + + ngOnDestroy(): void { + this.loading.complete(); + } + + public loginFromCode(params: Params) { + if (!params.code) { + return; + } + + this.loading.on(); + this._log.debug('Handling access token: ' + params.code) + const refresh = this.getToken({ + grantType: 'authorization_code', + code: params.code, + redirectUri: location.origin + '/' + this._config.getConfigurationSubtree(['services', 'auth', 'loginRedirect']), + }); + refresh.subscribe( + it => { + this.loading.off(); + if (it) { + this.redirectToHome(); + } + }, + ); + } + + public redirectToSso(): void { + let redirectUrl: string = this.getRedirectUrl(); + this._log.info("Redirecting to " + redirectUrl) + window.location.href = redirectUrl; + } + + private getRedirectUrl(): string { + // const myQuery = this._ssoConfig['login'] + '?'; + // const options: { [index: string]: string } = { + // client_id: this._authConfig.sso['clientID'] as string, + // redirect_uri: location.origin + '/' + this._config.getConfigurationSubtree(['services', 'auth', 'loginRedirect']), + // response_type: 'code', + // scope: this._config.getConfigurationSubtree(['providers', 'auth', 'sso', 'scopes']).join(' '), + // }; + // return myQuery + Object.keys(options).map( + // key => { + // return encodeURIComponent(key) + '=' + encodeURIComponent(options[key]); + // }, + // ).join('&'); + return 'https://google.com'; + } + + private getToken(body: any): Observable { + // const url = this._authConfig.sso['refreshUrl']; + // if (!url) { + // return throwError(new Error('Refresh URL is not defined in the config [nae.providers.auth.sso.refreshUrl]')); + // } + // return this._http.post(url, body, + // {headers: {'Content-Type': 'application/json'}}).pipe( + // catchError(error => { + // this.loading.off(); + // this._snackbar.openErrorSnackBar('Pri pokuse o prihlásenie došlo k neočakávanej chybe.'); + // if (error instanceof HttpErrorResponse && (error.status === 401 || error.status === 400)) { + // return throwError(error); + // } else { + // return throwError(error); + // } + // }), + // ); + return of() + } + + private redirectToHome() { + this._router.navigate(['/portal']).then((value) => { + this._log.debug('Routed to ' + value); + }); + } + +} diff --git a/projects/netgrif-components-core/src/lib/forms/public-api.ts b/projects/netgrif-components-core/src/lib/forms/public-api.ts index 1d96fe436f..ee45a0c708 100644 --- a/projects/netgrif-components-core/src/lib/forms/public-api.ts +++ b/projects/netgrif-components-core/src/lib/forms/public-api.ts @@ -1,5 +1,6 @@ export * from './email-submission/abstract-email-submission-form.component'; export * from './login/abstract-login-form.component'; +export * from './login/login-sso/abstract-login-sso.component'; export * from './registration/abstract-registration-form.component'; export * from './forgotten-password/abstract-forgotten-password.component'; export * from './models/abstract-registration.component'; diff --git a/projects/netgrif-components/src/lib/forms/login/login-form.component.html b/projects/netgrif-components/src/lib/forms/login/login-form.component.html index 2737866402..a0182bd078 100644 --- a/projects/netgrif-components/src/lib/forms/login/login-form.component.html +++ b/projects/netgrif-components/src/lib/forms/login/login-form.component.html @@ -40,6 +40,9 @@ {{ 'forms.login.loginButton' | translate}} +
+ +
diff --git a/projects/netgrif-components/src/lib/forms/login/login-form.component.ts b/projects/netgrif-components/src/lib/forms/login/login-form.component.ts index 67d8839c71..792a898d66 100644 --- a/projects/netgrif-components/src/lib/forms/login/login-form.component.ts +++ b/projects/netgrif-components/src/lib/forms/login/login-form.component.ts @@ -1,6 +1,6 @@ import {Component} from '@angular/core'; import {FormBuilder} from '@angular/forms'; -import {AbstractLoginFormComponent, UserService} from '@netgrif/components-core'; +import {AbstractLoginFormComponent, ConfigurationService, UserService} from '@netgrif/components-core'; @Component({ selector: 'nc-login-form', @@ -8,7 +8,7 @@ import {AbstractLoginFormComponent, UserService} from '@netgrif/components-core' styleUrls: ['./login-form.component.scss'] }) export class LoginFormComponent extends AbstractLoginFormComponent { - constructor(formBuilder: FormBuilder, protected _userService: UserService) { - super(formBuilder, _userService); + constructor(formBuilder: FormBuilder, protected _userService: UserService, protected _config: ConfigurationService) { + super(formBuilder, _userService, _config); } } diff --git a/projects/netgrif-components/src/lib/forms/login/login-form.module.ts b/projects/netgrif-components/src/lib/forms/login/login-form.module.ts index fde1854200..2466b04931 100644 --- a/projects/netgrif-components/src/lib/forms/login/login-form.module.ts +++ b/projects/netgrif-components/src/lib/forms/login/login-form.module.ts @@ -4,11 +4,12 @@ import {FlexLayoutModule} from '@ngbracket/ngx-layout'; import {ReactiveFormsModule} from '@angular/forms'; import {LoginFormComponent} from './login-form.component'; import {MaterialModule, TranslateLibModule} from '@netgrif/components-core'; +import {LoginSsoComponent} from "./login-sso/login-sso.component"; @NgModule({ - declarations: [LoginFormComponent], - exports: [LoginFormComponent], + declarations: [LoginFormComponent, LoginSsoComponent], + exports: [LoginFormComponent, LoginSsoComponent], imports: [ CommonModule, MaterialModule, diff --git a/projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.html b/projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.html new file mode 100644 index 0000000000..23934517d7 --- /dev/null +++ b/projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.html @@ -0,0 +1,9 @@ + diff --git a/projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.scss b/projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.spec.ts b/projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.spec.ts new file mode 100644 index 0000000000..37d77c8da1 --- /dev/null +++ b/projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.spec.ts @@ -0,0 +1,27 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LoginSsoComponent } from './login-sso.component'; + +// todo 2118 + +xdescribe('LoginSsoComponent', () => { + let component: LoginSsoComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ LoginSsoComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(LoginSsoComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.ts b/projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.ts new file mode 100644 index 0000000000..0c854da229 --- /dev/null +++ b/projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.ts @@ -0,0 +1,22 @@ +import {HttpClient} from '@angular/common/http'; +import {Component} from '@angular/core'; +import {ActivatedRoute, Router} from '@angular/router'; +import {AbstractLoginSsoComponent, ConfigurationService, LoggerService, SnackBarService} from '@netgrif/components-core'; + +@Component({ + selector: 'nc-login-sso', + templateUrl: './login-sso.component.html', + styleUrls: ['./login-sso.component.scss'], +}) +export class LoginSsoComponent extends AbstractLoginSsoComponent { + constructor( + protected _config: ConfigurationService, + protected _http: HttpClient, + protected _snackbar: SnackBarService, + protected _log: LoggerService, + protected _router: Router, + protected _activeRouter: ActivatedRoute, + ) { + super(_config, _http, _snackbar, _log, _router, _activeRouter); + } +} diff --git a/projects/netgrif-components/src/lib/forms/public-api.ts b/projects/netgrif-components/src/lib/forms/public-api.ts index 694bc6b239..ec27a47c22 100644 --- a/projects/netgrif-components/src/lib/forms/public-api.ts +++ b/projects/netgrif-components/src/lib/forms/public-api.ts @@ -1,6 +1,7 @@ /* COMPONENTS */ export * from './email-submission/email-submission-form.component'; export * from './login/login-form.component'; +export * from './login/login-sso/login-sso.component'; export * from './registration/registration-form.component'; export * from './forgotten-password/forgotten-password-form.component'; export * from './change-password/change-password-form.component'; From b842c457ea0d06f3267bad06f4a64d4c750f6ac3 Mon Sep 17 00:00:00 2001 From: chvostek Date: Mon, 2 Jun 2025 13:05:20 +0200 Subject: [PATCH 2/5] [NAE-2118] Implement OpenID Connector Auth for Admin node - implement redirect to iam --- nae.json | 4 ++- .../src/commons/schema.ts | 1 + .../login-sso/abstract-login-sso.component.ts | 25 +++++++++---------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/nae.json b/nae.json index b28e3ecb71..1c0ceecdff 100644 --- a/nae.json +++ b/nae.json @@ -22,7 +22,9 @@ "jwtBearer": "X-Jwt-Token", "sso": { "enable": true, - "redirectUrl": "https://netgrif.com" + "clientId": "cluster-worker", + "redirectUrl": "https://iam.mudu.dev.netgrif.cloud/realms/netgrif-cloud-testing/protocol/openid-connect/auth", + "scopes": ["openid","email","profile","roles"] } }, "resources": [ diff --git a/projects/netgrif-components-core/src/commons/schema.ts b/projects/netgrif-components-core/src/commons/schema.ts index 15b3939c39..e4c23bb598 100644 --- a/projects/netgrif-components-core/src/commons/schema.ts +++ b/projects/netgrif-components-core/src/commons/schema.ts @@ -54,6 +54,7 @@ export interface Auth { export interface Sso { enable: boolean; redirectUrl: string; + clientId: string; scopes: Array; } diff --git a/projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.ts b/projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.ts index a9c8d59095..c46fa65d38 100644 --- a/projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.ts +++ b/projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.ts @@ -69,19 +69,18 @@ export abstract class AbstractLoginSsoComponent implements OnDestroy { } private getRedirectUrl(): string { - // const myQuery = this._ssoConfig['login'] + '?'; - // const options: { [index: string]: string } = { - // client_id: this._authConfig.sso['clientID'] as string, - // redirect_uri: location.origin + '/' + this._config.getConfigurationSubtree(['services', 'auth', 'loginRedirect']), - // response_type: 'code', - // scope: this._config.getConfigurationSubtree(['providers', 'auth', 'sso', 'scopes']).join(' '), - // }; - // return myQuery + Object.keys(options).map( - // key => { - // return encodeURIComponent(key) + '=' + encodeURIComponent(options[key]); - // }, - // ).join('&'); - return 'https://google.com'; + const myQuery = this._ssoConfig.redirectUrl + '?'; + const options: { [index: string]: string } = { + client_id: this._ssoConfig.clientId, + redirect_uri: location.origin + '/' + this._config.getConfigurationSubtree(['services', 'auth', 'toLoginRedirect']), + response_type: 'code', + scope: this._ssoConfig.scopes.join(' '), + }; + return myQuery + Object.keys(options).map( + key => { + return encodeURIComponent(key) + '=' + encodeURIComponent(options[key]); + }, + ).join('&'); } private getToken(body: any): Observable { From 3ac92bb46c5b451ed86c0441f285530a76f80fa2 Mon Sep 17 00:00:00 2001 From: chvostek Date: Mon, 2 Jun 2025 15:28:54 +0200 Subject: [PATCH 3/5] [NAE-2118] Implement OpenID Connector Auth for Admin node - implement backend call with access token --- nae.json | 1 + .../src/commons/schema.ts | 1 + .../login-sso/abstract-login-sso.component.ts | 63 +++++++++---------- .../login/login-sso/login-sso.component.ts | 4 +- 4 files changed, 34 insertions(+), 35 deletions(-) diff --git a/nae.json b/nae.json index 1c0ceecdff..bd926bb8d0 100644 --- a/nae.json +++ b/nae.json @@ -24,6 +24,7 @@ "enable": true, "clientId": "cluster-worker", "redirectUrl": "https://iam.mudu.dev.netgrif.cloud/realms/netgrif-cloud-testing/protocol/openid-connect/auth", + "refreshUrl": "http://localhost:8800/api/oidc/auth/login", "scopes": ["openid","email","profile","roles"] } }, diff --git a/projects/netgrif-components-core/src/commons/schema.ts b/projects/netgrif-components-core/src/commons/schema.ts index e4c23bb598..d02835a32e 100644 --- a/projects/netgrif-components-core/src/commons/schema.ts +++ b/projects/netgrif-components-core/src/commons/schema.ts @@ -54,6 +54,7 @@ export interface Auth { export interface Sso { enable: boolean; redirectUrl: string; + refreshUrl: string; clientId: string; scopes: Array; } diff --git a/projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.ts b/projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.ts index c46fa65d38..7b6e3f1343 100644 --- a/projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.ts +++ b/projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.ts @@ -1,13 +1,14 @@ import {Component, OnDestroy} from "@angular/core"; import {ActivatedRoute, Params, Router} from "@angular/router"; -import {Observable, of, throwError} from "rxjs"; +import {Observable, throwError} from "rxjs"; import {catchError} from "rxjs/operators"; -import {HttpClient, HttpErrorResponse} from "@angular/common/http"; +import {HttpClient} from "@angular/common/http"; import {ConfigurationService} from "../../../configuration/configuration.service"; import {LoggerService} from '../../../logger/services/logger.service'; import {LoadingEmitter} from '../../../utility/loading-emitter'; import {SnackBarService} from "../../../snack-bar/services/snack-bar.service"; import {Sso} from "../../../../commons/schema"; +import {TranslateService} from "@ngx-translate/core"; @Component({ @@ -26,6 +27,7 @@ export abstract class AbstractLoginSsoComponent implements OnDestroy { protected _log: LoggerService, protected _router: Router, protected _activeRouter: ActivatedRoute, + protected _translate: TranslateService ) { this._ssoConfig = this._config.getConfigurationSubtree(['providers', 'auth', 'sso']); this.loading = new LoadingEmitter(); @@ -40,6 +42,12 @@ export abstract class AbstractLoginSsoComponent implements OnDestroy { this.loading.complete(); } + public redirectToSso(): void { + let redirectUrl: string = this.getRedirectUrl(); + this._log.info("Redirecting to " + redirectUrl) + window.location.href = redirectUrl; + } + public loginFromCode(params: Params) { if (!params.code) { return; @@ -47,27 +55,21 @@ export abstract class AbstractLoginSsoComponent implements OnDestroy { this.loading.on(); this._log.debug('Handling access token: ' + params.code) - const refresh = this.getToken({ + const token$ = this.getToken({ grantType: 'authorization_code', code: params.code, - redirectUri: location.origin + '/' + this._config.getConfigurationSubtree(['services', 'auth', 'loginRedirect']), + redirectUri: location.origin + '/' + this._config.getConfigurationSubtree(['services', 'auth', 'toLoginRedirect']), }); - refresh.subscribe( - it => { + token$.subscribe( + token => { this.loading.off(); - if (it) { + if (!!token) { this.redirectToHome(); } }, ); } - public redirectToSso(): void { - let redirectUrl: string = this.getRedirectUrl(); - this._log.info("Redirecting to " + redirectUrl) - window.location.href = redirectUrl; - } - private getRedirectUrl(): string { const myQuery = this._ssoConfig.redirectUrl + '?'; const options: { [index: string]: string } = { @@ -84,29 +86,22 @@ export abstract class AbstractLoginSsoComponent implements OnDestroy { } private getToken(body: any): Observable { - // const url = this._authConfig.sso['refreshUrl']; - // if (!url) { - // return throwError(new Error('Refresh URL is not defined in the config [nae.providers.auth.sso.refreshUrl]')); - // } - // return this._http.post(url, body, - // {headers: {'Content-Type': 'application/json'}}).pipe( - // catchError(error => { - // this.loading.off(); - // this._snackbar.openErrorSnackBar('Pri pokuse o prihlásenie došlo k neočakávanej chybe.'); - // if (error instanceof HttpErrorResponse && (error.status === 401 || error.status === 400)) { - // return throwError(error); - // } else { - // return throwError(error); - // } - // }), - // ); - return of() + const url = this._ssoConfig.refreshUrl; + if (!url) { + return throwError(() => new Error('Refresh URL is not defined in the config [nae.providers.auth.sso.refreshUrl]')); + } + return this._http.post(url, body, + {headers: {'Content-Type': 'application/json'}}).pipe( + catchError(error => { + this.loading.off(); + this._snackbar.openErrorSnackBar(this._translate.instant('forms.login.wrongCredentials')); + return throwError(() => error); + }), + ); } private redirectToHome() { - this._router.navigate(['/portal']).then((value) => { - this._log.debug('Routed to ' + value); - }); + this._router.navigate(['/' + this._config.getConfigurationSubtree(['services', 'auth', 'onLoginRedirect'])]) + .then((value) => { this._log.debug('Routed to ' + value); }); } - } diff --git a/projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.ts b/projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.ts index 0c854da229..ad0337e287 100644 --- a/projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.ts +++ b/projects/netgrif-components/src/lib/forms/login/login-sso/login-sso.component.ts @@ -2,6 +2,7 @@ import {HttpClient} from '@angular/common/http'; import {Component} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; import {AbstractLoginSsoComponent, ConfigurationService, LoggerService, SnackBarService} from '@netgrif/components-core'; +import {TranslateService} from "@ngx-translate/core"; @Component({ selector: 'nc-login-sso', @@ -16,7 +17,8 @@ export class LoginSsoComponent extends AbstractLoginSsoComponent { protected _log: LoggerService, protected _router: Router, protected _activeRouter: ActivatedRoute, + protected _translate: TranslateService ) { - super(_config, _http, _snackbar, _log, _router, _activeRouter); + super(_config, _http, _snackbar, _log, _router, _activeRouter, _translate); } } From df7dd137736096883ed380c9e00299de92425031 Mon Sep 17 00:00:00 2001 From: chvostek Date: Wed, 11 Jun 2025 08:08:58 +0200 Subject: [PATCH 4/5] [NAE-2118] Implement OpenID Connector Auth for Admin node - add realm id request placeholder --- nae.json | 2 +- .../lib/forms/login/login-sso/abstract-login-sso.component.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/nae.json b/nae.json index bd926bb8d0..a0479bd552 100644 --- a/nae.json +++ b/nae.json @@ -24,7 +24,7 @@ "enable": true, "clientId": "cluster-worker", "redirectUrl": "https://iam.mudu.dev.netgrif.cloud/realms/netgrif-cloud-testing/protocol/openid-connect/auth", - "refreshUrl": "http://localhost:8800/api/oidc/auth/login", + "refreshUrl": "http://localhost:8800/api/auth/login", "scopes": ["openid","email","profile","roles"] } }, diff --git a/projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.ts b/projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.ts index 7b6e3f1343..2b71c0a0fa 100644 --- a/projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.ts +++ b/projects/netgrif-components-core/src/lib/forms/login/login-sso/abstract-login-sso.component.ts @@ -58,6 +58,7 @@ export abstract class AbstractLoginSsoComponent implements OnDestroy { const token$ = this.getToken({ grantType: 'authorization_code', code: params.code, + realmId: '', // todo send realm id redirectUri: location.origin + '/' + this._config.getConfigurationSubtree(['services', 'auth', 'toLoginRedirect']), }); token$.subscribe( From 8e3c165fe765cb8c43a92d1843d4ece093d70d3c Mon Sep 17 00:00:00 2001 From: chvostek Date: Mon, 16 Jun 2025 14:05:58 +0200 Subject: [PATCH 5/5] [NAE-2118] Implement OpenID Connector Auth for Admin node - preconfigure nae.json for local development --- nae.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nae.json b/nae.json index a0479bd552..93800125ad 100644 --- a/nae.json +++ b/nae.json @@ -4,7 +4,7 @@ "providers": { "auth": { "address": "http://localhost:8080/api/", - "authentication": "Basic", + "authentication": "BasicWithRealm", "endpoints": { "login": "auth/login", "logout": "auth/logout", @@ -14,7 +14,7 @@ "verify": "auth/token/verify", "invite": "auth/invite", "reset": "auth/reset", - "recover": "/auth/recover" + "recover": "auth/recover" }, "sessionBearer": "X-Auth-Token", "sessionTimeoutEnabled": false, @@ -22,7 +22,7 @@ "jwtBearer": "X-Jwt-Token", "sso": { "enable": true, - "clientId": "cluster-worker", + "clientId": "dev-cluster-worker", "redirectUrl": "https://iam.mudu.dev.netgrif.cloud/realms/netgrif-cloud-testing/protocol/openid-connect/auth", "refreshUrl": "http://localhost:8800/api/auth/login", "scopes": ["openid","email","profile","roles"]