...
  View open merge request
Commits (2)
  • Daniel Gerhardt's avatar
    Add support for SSO to auth service · d217047c
    Daniel Gerhardt authored
    This implementation opens the SSO login page in a popup and retrieves
    authentication details from the API once the popup is closed. Components
    have not yet been adjusted to support SSO.
    d217047c
  • Daniel Gerhardt's avatar
    Add SSO buttons to login dialog · b8b90371
    Daniel Gerhardt authored
    SSO login buttons are dynamically added based on the authentication
    provider config received from backend API.
    b8b90371
......@@ -25,6 +25,9 @@
<button id="focus_button_user" class="login" mat-flat-button type="submit" aria-labelledby="login-description">
{{ 'login.login' | translate }}
</button>
<button *ngFor="let provider of ssoProviders" (click)="loginViaSso(provider.id)" class="sso" mat-flat-button type="button">
{{ 'login.login-with' | translate }} {{ provider.title }}
</button>
<button id="focus_button_guest" (click)="guestLogin()" class="guest" mat-flat-button type="button" aria-labelledby="guest-login-description"
matTooltip="{{'login.guest-login-tooltip' | translate}}">
{{ 'login.guest-login' | translate }}
......
......@@ -10,6 +10,7 @@ import { UserActivationComponent } from '../../home/_dialogs/user-activation/use
import { PasswordResetComponent } from '../../home/_dialogs/password-reset/password-reset.component';
import { RegisterComponent } from '../../home/_dialogs/register/register.component';
import { EventService } from '../../../services/util/event.service';
import { AuthenticationProviderType } from '../../../models/api-config';
export class LoginErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
......@@ -42,6 +43,7 @@ export class LoginComponent implements OnInit, OnChanges {
public notificationService: NotificationService,
public dialog: MatDialog,
public eventService: EventService,
private apiConfigService: ApiConfigService,
@Inject(MAT_DIALOG_DATA) public data: any) {
}
......@@ -64,6 +66,16 @@ export class LoginComponent implements OnInit, OnChanges {
}
}
get ssoProviders() {
return this.providers(AuthenticationProviderType.SSO);
}
providers(type?: AuthenticationProviderType) {
return (type != null)
? this.apiConfigService.getAuthProviders().filter((p) => p.type === type)
: this.apiConfigService.getAuthProviders();
}
activateUser(): void {
this.dialog.open(UserActivationComponent, {
width: '350px',
......@@ -97,6 +109,10 @@ export class LoginComponent implements OnInit, OnChanges {
this.authenticationService.guestLogin(this.role).subscribe(loginSuccessful => this.checkLogin(loginSuccessful));
}
loginViaSso(providerId: string): void {
this.authenticationService.loginViaSso(providerId, this.role).subscribe(loginSuccessful => this.checkLogin(loginSuccessful));
}
private checkLogin(loginSuccessful: string) {
if (loginSuccessful === 'true') {
this.translationService.get('login.login-successful').subscribe(message => {
......
import { catchError, map } from 'rxjs/operators';
import { catchError, map, concatMap, filter, take } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { User } from '../../models/user';
import { Observable , of , BehaviorSubject } from 'rxjs';
import { Observable, of, BehaviorSubject, timer } from 'rxjs';
import { UserRole } from '../../models/user-roles.enum';
import { DataStoreService } from '../util/data-store.service';
import { EventService } from '../util/event.service';
......@@ -22,7 +22,8 @@ export class AuthenticationService {
register: '/register',
registered: '/registered',
resetPassword: '/resetpassword',
guest: '/guest'
guest: '/guest',
sso: '/sso'
};
private httpOptions = {
headers: new HttpHeaders({})
......@@ -89,6 +90,30 @@ export class AuthenticationService {
return this.checkLogin(this.http.post<ClientAuthentication>(connectionUrl, null, this.httpOptions), userRole, true);
}
/**
* Open the SSO login page in a popup and check the result.
*
* @param providerId ID of the SSO provider
* @param userRole User role for the UI
*/
loginViaSso(providerId: string, userRole: UserRole): Observable<string> {
const ssoUrl = this.apiUrl.base + this.apiUrl.auth + this.apiUrl.sso + '/' + providerId;
const loginUrl = this.apiUrl.base + this.apiUrl.auth + this.apiUrl.login + '?refresh=true';
const popupW = 500;
const popupH = 500;
const popupX = window.top.screenX + window.top.outerWidth / 2 - popupW / 2;
const popupY = window.top.screenY + window.top.outerHeight / 2 - popupH / 2;
const popup = window.open(ssoUrl, 'auth_popup',
`left=${popupX},top=${popupY},width=${popupW},height=${popupH},resizable`);
const auth = timer(0, 500).pipe(
map(() => popup.closed),
filter((closed) => closed),
concatMap(() => this.http.post<ClientAuthentication>(loginUrl, null, { withCredentials: true })),
take(1));
return this.checkLogin(auth, userRole, false);
}
register(email: string, password: string): Observable<boolean> {
const connectionUrl: string = this.apiUrl.base + this.apiUrl.user + this.apiUrl.register;
......
......@@ -109,6 +109,7 @@
"header": "Anmelden",
"input-incorrect": "Bitte prüfe deine Eingaben.",
"login": "Anmelden mit Konto",
"login-with": "Anmelden mit",
"login-data-incorrect": "Benutzername oder Passwort falsch",
"login-description": "Mit den eingegebenen Kontodaten anmelden",
"login-successful": "Anmeldung erfolgreich",
......
......@@ -111,6 +111,7 @@
"header": "Log in",
"input-incorrect": "Please check your data.",
"login": "Log in with account",
"login-with": "Log in with",
"login-data-incorrect": "Username or password incorrect",
"login-description": "Log in with the entered account data",
"login-successful": "Login successful",
......