Skip to content

Commit

Permalink
mgr/dashboard: securely store remote cluster token
Browse files Browse the repository at this point in the history
Instead of using the localStorage use cookies for storing the token more
securely

Signed-off-by: Nizamudeen A <nia@redhat.com>
  • Loading branch information
nizamial09 committed Mar 16, 2024
1 parent 758a0bc commit 4aac1a0
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 8 deletions.
18 changes: 18 additions & 0 deletions src/pybind/mgr/dashboard/frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/pybind/mgr/dashboard/frontend/package.json
Expand Up @@ -72,6 +72,7 @@
"ng-block-ui": "3.0.2",
"ng-click-outside": "7.0.0",
"ng2-charts": "4.1.1",
"ngx-cookie-service": "17.1.0",
"ngx-pipe-function": "1.0.0",
"ngx-toastr": "17.0.2",
"rxjs": "6.6.3",
Expand Down
Expand Up @@ -18,6 +18,7 @@ import { CellTemplate } from '~/app/shared/enum/cell-template.enum';
import { MultiCluster } from '~/app/shared/models/multi-cluster';
import { SummaryService } from '~/app/shared/services/summary.service';
import { Router } from '@angular/router';
import { CookiesService } from '~/app/shared/services/cookie.service';

@Component({
selector: 'cd-multi-cluster-list',
Expand Down Expand Up @@ -48,7 +49,8 @@ export class MultiClusterListComponent {
public actionLabels: ActionLabelsI18n,
private notificationService: NotificationService,
private authStorageService: AuthStorageService,
private modalService: ModalService
private modalService: ModalService,
private cookieService: CookiesService
) {
this.tableActions = [
{
Expand Down Expand Up @@ -189,6 +191,7 @@ export class MultiClusterListComponent {
itemNames: [cluster['cluster_alias'] + ' - ' + cluster['user']],
submitAction: () =>
this.multiClusterService.deleteCluster(cluster['name'], cluster['user']).subscribe(() => {
this.cookieService.deleteToken(cluster['cluster_alias']);
this.modalRef.close();
this.notificationService.show(
NotificationType.success,
Expand Down
Expand Up @@ -9,6 +9,7 @@ import { Icons } from '~/app/shared/enum/icons.enum';
import { MultiCluster } from '~/app/shared/models/multi-cluster';
import { Permissions } from '~/app/shared/models/permissions';
import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
import { CookiesService } from '~/app/shared/services/cookie.service';
import {
FeatureTogglesMap$,
FeatureTogglesService
Expand Down Expand Up @@ -56,7 +57,8 @@ export class NavigationComponent implements OnInit, OnDestroy {
private featureToggles: FeatureTogglesService,
private telemetryNotificationService: TelemetryNotificationService,
public prometheusAlertService: PrometheusAlertService,
private motdNotificationService: MotdNotificationService
private motdNotificationService: MotdNotificationService,
private cookieService: CookiesService
) {
this.permissions = this.authStorageService.getPermissions();
this.enabledFeature$ = this.featureToggles.get();
Expand Down Expand Up @@ -178,7 +180,12 @@ export class NavigationComponent implements OnInit, OnDestroy {
onClusterSelection(value: object) {
this.multiClusterService.setCluster(value).subscribe(
(resp: any) => {
localStorage.setItem('cluster_api_url', value['url']);
if (value['cluster_alias'] === 'local-cluster') {
localStorage.setItem('cluster_api_url', '');
} else {
localStorage.setItem('current_cluster_name', value['cluster_alias']);
localStorage.setItem('cluster_api_url', value['url']);
}
this.selectedCluster = this.clustersMap.get(`${value['url']}-${value['user']}`) || {};
const clustersConfig = resp['config'];
if (clustersConfig && typeof clustersConfig === 'object') {
Expand All @@ -192,9 +199,10 @@ export class NavigationComponent implements OnInit, OnDestroy {

if (
clusterName === this.selectedCluster['name'] &&
clusterUser === this.selectedCluster['user']
clusterUser === this.selectedCluster['user'] &&
clusterDetails['cluster_alias'] !== 'local-cluster'
) {
localStorage.setItem('token_of_selected_cluster', clusterToken);
this.cookieService.setToken(clusterDetails['cluster_alias'], clusterToken);
}
});
});
Expand Down
Expand Up @@ -20,6 +20,7 @@ import { NotificationService } from './notification.service';
import { MultiClusterService } from '../api/multi-cluster.service';
import { SummaryService } from './summary.service';
import { AuthStorageService } from './auth-storage.service';
import { CookiesService } from './cookie.service';

export class CdHttpErrorResponse extends HttpErrorResponse {
preventDefault: Function;
Expand All @@ -37,7 +38,8 @@ export class ApiInterceptorService implements HttpInterceptor {
public notificationService: NotificationService,
private summaryService: SummaryService,
private authStorageService: AuthStorageService,
private multiClusterService: MultiClusterService
private multiClusterService: MultiClusterService,
private cookieService: CookiesService
) {
this.multiClusterService.subscribe((resp: any) => {
const clustersConfig = resp['config'];
Expand Down Expand Up @@ -91,14 +93,13 @@ export class ApiInterceptorService implements HttpInterceptor {
'api/multi-cluster/auth'
];

const token = localStorage.getItem('token_of_selected_cluster');

if (
!currentRoute.includes('login') &&
!ALWAYS_TO_HUB_APIs.includes(request.url) &&
apiUrl &&
!apiUrl.includes(origin)
) {
const token = this.cookieService.getToken(localStorage.getItem('cluster_alias'));
reqWithVersion = reqWithVersion.clone({
url: `${apiUrl}${reqWithVersion.url}`,
setHeaders: {
Expand Down
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';

import { CookiesService } from './cookie.service';

describe('CookieService', () => {
let service: CookiesService;

beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(CookiesService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,21 @@
import { Injectable } from '@angular/core';
import { CookieService } from 'ngx-cookie-service';

@Injectable({
providedIn: 'root'
})
export class CookiesService {
constructor(private cookieService: CookieService) {}

setToken(name: string, token: string) {
this.cookieService.set(name, token, null, null, null, true, 'Strict');
}

getToken(name: string): string {
return this.cookieService.get(name);
}

deleteToken(name: string) {
this.cookieService.delete(name);
}
}

0 comments on commit 4aac1a0

Please sign in to comment.