Skip to content

Commit

Permalink
Merge branch 'main' into person/hzhristova/improve-errors-messages-vi…
Browse files Browse the repository at this point in the history
…sibility
  • Loading branch information
hzhristova committed Apr 27, 2023
2 parents b6d44a5 + 8a96105 commit fe69387
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ export interface AppConfig {
}

export interface Auth {
skipAuth?: false;

// Used for producing the AuthConfig.customQueryParams mapping for `orgLink` and `targetUri`
consoleCloudUrl?: string;
orgLinkRoot?: string;
// $window.location.origin is replaced with the corresponding value dynamically upon loading,
// see AppConfigService
authConfig?: AuthConfig;

resourceServer?: OAuthResourceServerConfig;
// Used for token auto-refresh capability, in case a token is about to expire.
refreshTokenConfig?: RefreshTokenConfig;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ export class AppConfigService {
return this.appConfig;
}

getSkipAuth(): boolean {
return this.appConfig.auth.skipAuth;
}

getAuthCodeFlowConfig(): AuthConfig {
if (this.getSkipAuth()) return new AuthConfig();
const replaceWindowLocationOrigin = (str: string): string => {
return str?.replace('$window.location.origin', window.location.origin);
};
Expand All @@ -42,6 +47,7 @@ export class AppConfigService {
}

getRefreshTokenConfig(): RefreshTokenConfig {
if (this.getSkipAuth()) return null;
return this.getConfig()?.auth.refreshTokenConfig;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
~ SPDX-License-Identifier: Apache-2.0
-->

<clr-main-container [attr.data-automation]="!!idToken ? 'vdk' : null">
<ng-container *ngIf="idToken">
<clr-main-container
[attr.data-automation]="skipAuth || !!idToken ? 'vdk' : null"
>
<ng-container *ngIf="skipAuth || idToken">
<header class="header-7">
<div class="branding">
<a href="..." class="nav-link">
Expand All @@ -14,7 +16,7 @@
>
</a>
</div>
<div class="header-actions">
<div class="header-actions" *ngIf="!skipAuth">
<clr-dropdown>
<button
class="nav-text"
Expand Down Expand Up @@ -108,7 +110,7 @@
</ng-container>
</clr-main-container>

<div *ngIf="!idToken" class="vdk-main__spinner-container">
<div *ngIf="!skipAuth && !idToken" class="vdk-main__spinner-container">
<div class="checking-user">
<div class="loading-spinner">
<h2 class="loading-title">Loading Data</h2>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,55 @@ import {
UrlOpenerService
} from '@versatiledatakit/shared';

import { AppConfig } from './app-config.model';

import { AppConfigService } from './app-config.service';

import { AppComponent } from './app.component';

describe('AppComponent', () => {
let routerServiceStub: jasmine.SpyObj<RouterService>;
let oAuthServiceStub: jasmine.SpyObj<OAuthService>;
let navigationServiceStub: jasmine.SpyObj<NavigationService>;
let viewContainerRefStub: jasmine.SpyObj<ViewContainerRef>;
let dynamicComponentsServiceStub: jasmine.SpyObj<DynamicComponentsService>;
let confirmationServiceStub: jasmine.SpyObj<ConfirmationService>;
let urlOpenerServiceStub: jasmine.SpyObj<UrlOpenerService>;
let appConfigServiceStub: jasmine.SpyObj<AppConfigService>;
const configureTestingModule = (providersAdditional: any[]) => {
const providersBase = [
UrlHelperService,
{ provide: NavigationService, useValue: navigationServiceStub },
{ provide: RouterService, useValue: routerServiceStub },
{ provide: ViewContainerRef, useValue: viewContainerRefStub },
{ provide: DynamicComponentsService, useValue: dynamicComponentsServiceStub },
{ provide: ConfirmationService, useValue: confirmationServiceStub },
{ provide: UrlOpenerService, useValue: urlOpenerServiceStub },
{ provide: AppConfigService, useValue: appConfigServiceStub }
];
TestBed.configureTestingModule({
schemas: [NO_ERRORS_SCHEMA],
declarations: [AppComponent],
imports: [],
providers: providersBase.concat(providersAdditional)
});
};

beforeEach(() => {
routerServiceStub = jasmine.createSpyObj<RouterService>('routerService', ['getState']);
oAuthServiceStub = jasmine.createSpyObj<OAuthService>('oAuthService', [
navigationServiceStub = jasmine.createSpyObj<NavigationService>('navigationService', ['initialize']);
appConfigServiceStub = jasmine.createSpyObj<AppConfigService>('appConfigService', [
'getConfig',
'getAuthCodeFlowConfig',
'getSkipAuth'
]);
viewContainerRefStub = jasmine.createSpyObj<ViewContainerRef>('viewContainerRefStub', ['createComponent']);
dynamicComponentsServiceStub = jasmine.createSpyObj<DynamicComponentsService>('dynamicComponentsServiceStub', ['initialize']);
confirmationServiceStub = jasmine.createSpyObj<ConfirmationService>('confirmationServiceStub', ['initialize']);
urlOpenerServiceStub = jasmine.createSpyObj<UrlOpenerService>('urlOpenerServiceStub', ['initialize']);
routerServiceStub.getState.and.returnValue(new Subject());
});

it('should create the app with auth enabled', () => {
appConfigServiceStub.getSkipAuth.and.returnValue(false);
const oAuthServiceStub = jasmine.createSpyObj<OAuthService>('oAuthService', [
'configure',
'loadDiscoveryDocumentAndLogin',
'getAccessTokenExpiration',
Expand All @@ -46,41 +76,19 @@ describe('AppComponent', () => {
'getIdToken',
'getIdentityClaims'
]);
navigationServiceStub = jasmine.createSpyObj<NavigationService>('navigationService', ['initialize']);
viewContainerRefStub = jasmine.createSpyObj<ViewContainerRef>('viewContainerRefStub', ['createComponent']);
dynamicComponentsServiceStub = jasmine.createSpyObj<DynamicComponentsService>('dynamicComponentsServiceStub', ['initialize']);
confirmationServiceStub = jasmine.createSpyObj<ConfirmationService>('confirmationServiceStub', ['initialize']);
urlOpenerServiceStub = jasmine.createSpyObj<UrlOpenerService>('urlOpenerServiceStub', ['initialize']);
appConfigServiceStub = jasmine.createSpyObj<AppConfigService>('appConfigService', ['getConfig', 'getAuthCodeFlowConfig']);

routerServiceStub.getState.and.returnValue(new Subject());
oAuthServiceStub.getIdentityClaims.and.returnValue({});
oAuthServiceStub.loadDiscoveryDocumentAndLogin.and.returnValue(Promise.resolve(true));
oAuthServiceStub.getAccessTokenExpiration.and.returnValue(0);
oAuthServiceStub.refreshToken.and.returnValue(Promise.resolve({} as TokenResponse));
appConfigServiceStub.getConfig.and.returnValue({} as AppConfig);
configureTestingModule([{ provide: OAuthService, useValue: oAuthServiceStub }]);

TestBed.configureTestingModule({
schemas: [NO_ERRORS_SCHEMA],
declarations: [AppComponent],
imports: [],
providers: [
UrlHelperService,
{ provide: OAuthService, useValue: oAuthServiceStub },
{ provide: NavigationService, useValue: navigationServiceStub },
{ provide: RouterService, useValue: routerServiceStub },
{ provide: ViewContainerRef, useValue: viewContainerRefStub },
{ provide: DynamicComponentsService, useValue: dynamicComponentsServiceStub },
{ provide: ConfirmationService, useValue: confirmationServiceStub },
{ provide: UrlOpenerService, useValue: urlOpenerServiceStub },
{ provide: AppConfigService, useValue: appConfigServiceStub }
]
});
});

it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});

it('should create the app with auth skipped', () => {
appConfigServiceStub.getSkipAuth.and.returnValue(true);
configureTestingModule([]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { Component, OnInit, ViewContainerRef } from '@angular/core';
import { Component, OnInit, ViewContainerRef, Optional } from '@angular/core';

import { timer } from 'rxjs';

Expand All @@ -24,33 +24,42 @@ export class AppComponent implements OnInit {

constructor(
private readonly appConfigService: AppConfigService,
private readonly oauthService: OAuthService,
@Optional() private readonly oauthService: OAuthService,
private readonly navigationService: NavigationService,
private readonly viewContainerRef: ViewContainerRef,
private readonly dynamicComponentsService: DynamicComponentsService,
private readonly confirmationService: ConfirmationService,
private readonly urlOpenerService: UrlOpenerService
) {
this.oauthService.configure(appConfigService.getAuthCodeFlowConfig());
this.oauthService
.loadDiscoveryDocumentAndLogin()
.then(() => {
this.initTokenRefresh();
})
.catch(() => {
// No-op.
});
if (!this.skipAuth) {
this.oauthService.configure(appConfigService.getAuthCodeFlowConfig());
this.oauthService
.loadDiscoveryDocumentAndLogin()
.then(() => {
this.initTokenRefresh();
})
.catch(() => {
// No-op.
});
}
}

logout(): void {
if (this.skipAuth) return;
this.oauthService.logOut();
}

get skipAuth(): boolean {
return this.appConfigService.getSkipAuth();
}

get idToken(): string {
if (this.skipAuth) return null;
return this.oauthService.getIdToken();
}

get userName(): string {
if (this.skipAuth) return null;
return this.oauthService.getIdentityClaims() ? this.getIdentityClaim('username') : 'N/A';
}

Expand All @@ -65,6 +74,7 @@ export class AppComponent implements OnInit {
}

private getIdentityClaim(userNamePropName: string): string {
if (this.skipAuth) throw Error;
const identityClaims = this.oauthService.getIdentityClaims() as {
[key: string]: string;
};
Expand All @@ -73,6 +83,7 @@ export class AppComponent implements OnInit {
}

private initTokenRefresh() {
if (this.skipAuth) throw Error;
const refreshTokenConfig = this.appConfigService.getRefreshTokenConfig();
timer(refreshTokenConfig.start, AppComponent.toMillis(refreshTokenConfig.checkInterval)).subscribe(() => {
const remainiTimeMillis = this.oauthService.getAccessTokenExpiration() - Date.now();
Expand All @@ -86,6 +97,7 @@ export class AppComponent implements OnInit {
}

private setCustomTokenAttributes(redirectToConsole: boolean, defaultOrg: { refLink: string }) {
if (this.skipAuth) throw Error;
const linkOrgQuery = this.getOrgLinkFromQueryParams(defaultOrg);
const consoleCloudUrl = this.appConfigService.getConfig().auth.consoleCloudUrl;
this.oauthService.customQueryParams = {
Expand All @@ -99,6 +111,7 @@ export class AppComponent implements OnInit {
}

private getOrgLinkFromQueryParams(defaultOrg: { refLink: string }): string {
if (this.skipAuth) throw Error;
const params = new URLSearchParams(window.location.search);
const orgLinkUnderscored = params.get('org_link');
const orgLinkBase = params.get('orgLink');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,15 @@ export function lottiePlayerLoader() {
useValue: localStorage
},
{
deps: [AppConfigService],
provide: AuthConfig,
useFactory: (appConfig: AppConfigService) => () => appConfig.getAuthCodeFlowConfig()
},
{
deps: [AppConfigService],
provide: OAuthModuleConfig,
useFactory: (appConfig: AppConfigService) => ({
resourceServer: {
allowedUrls: appConfig.getConfig().auth.resourceServer.allowedUrls,
sendAccessToken: appConfig.getConfig().auth.resourceServer.sendAccessToken
}
resourceServer: appConfig.getConfig().auth.resourceServer
})
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,20 @@ export class AuthorizationInterceptor implements HttpInterceptor {
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const url = req.url.toLowerCase();
if (this.appConfigService.getSkipAuth()) {
return next.handle(req);
}
if (!this.moduleConfig) {
return next.handle(req);
}

if (!this.moduleConfig.resourceServer) {
return next.handle(req);
}

if (!this.moduleConfig.resourceServer.allowedUrls) {
return next.handle(req);
}

const url = req.url.toLowerCase();
if (!this.checkUrl(url)) {
return next.handle(req);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"auth": {
"skipAuth": false,
"consoleCloudUrl": "https://console-stg.cloud.vmware.com/",
"orgLinkRoot": "/csp/gateway/am/api/orgs/",
"authConfig": {
Expand Down

0 comments on commit fe69387

Please sign in to comment.